zoukankan      html  css  js  c++  java
  • springboot重新认识

    4.1.3.微服务的核心之springboot重新认识【上】

    3.1.springboot重新认识

    3.1.1.springboot的前世今生

    3.1.1.1.spring boot是什么?

      从spring framework开始,核心功能:IOC/DI和MVC,AOP.

      spring中bean自动注入,可以基于注解xml配置方式。基于spring+spring mvc +mybatis,即ssm框架开发web项目。

    往往需要进行多个文件配置。这个配置对于开发人员来说,也是繁重的工作量。

      spring是个好人呀,它说,我看开发人员很辛苦啊,我准备开发一个新产品,把配置文件的工作也给做了。让开发人员

    可以“零配置”搭建web项目。

      spring团队,再一想,基于ssm开发,还需要在pom.xml中添加很多依赖,也很是消耗开发人员的时间呀。这个添加依赖的

    工作,我们也来做了吧!于是,spring想出了starter思想,设计starter依赖包。开发时只要引入这个依赖包,spring开发的一些基本包

    依赖就可以省事了。

      spring 团队,在spring的基础上,开发了新产品springboot,在2014年发布1.0版本,它成为了一个更加轻量级的框架。

      springboot就具有基本功能:零配置,starter封装依赖,main启动项目。

    3.1.1.2.spring boot产生

      在2014年发布1.0版本。

    3.1.2.spring mvc项目构建与springboot构建web项目

    3.1.2.1.基于ssm框架构建web项目流程

    1.创建一个web项目工程【基于maven或gradle】

    2.pom.xml中添加相关依赖,spring+mybatis+mysql+servlet+...

    3.web.xml配置DispatcherServlet

    4.创建spring-mvc.xml配置【配置自动扫描,注解驱动。。。】

    5.创建Controller,及相关服务bean【添加spring-bean.xml配置。。。】

    6.启动项目,发布到tomcat

    这种流程,是每一个基于ssm开发web项目的通用模板。为了减少这个模板化创建过程,可以基于已经创建好的web项目结构,

    手动创建一个maven项目骨架。

      然后,通过命令行,输入基本参数,创建一个基本ssm项目模板。

    1.基于ssm搭建简单的web工程demo
    [1]使用maven的web骨架创建web工程

    工程结构如下所示:

     【2】pom.xml中添加相关依赖

    spring相关依赖:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
      </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-beans</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-expression</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>${spring.version}</version>
        </dependency>
    【2】修改web.xml,配置DispatcherServlet
    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      
      <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:dispatcher-servlet.xml</param-value>
        </init-param>
      </servlet>
      <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    </web-app>

    并且在resources资源目录下创建dispatcher-servlet.xml配置文件。

    注意:

      idea工具下使用maven搭建的新的web工程,默认是没有resources目录的。需要创建目录,如下所示。

    然后,创建dispatcher-servlet.xml配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
             http://www.springframework.org/schema/mvc http://www.springframework.org/schema/context/spring-mvc.xsd
             http://www.springframework.org/schema/aop http://www.springframework.org/schema/context/spring-aop.xsd"
           default-autowire="byName">
        <context:component-scan base-package="com.wf"/>
        <context:annotation-config/>
        <!--开启注解驱动-->
        <mvc:annotation-driven/>
        <!--定义视图解析器-->
        <bean id="view" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/views"/>
            <property name="suffix" value="*.jsp"/>
        </bean>
    </beans>
    【3】编写controller类
    package com.wf.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @ClassName HelloController
     * @Description 测试controller
     * @Author wf
     * @Date 2020/7/3 17:15
     * @Version 1.0
     */
    @RestController
    public class HelloController {
        @GetMapping("/test")
        public String test(){
            return "Hello World";
        }
    }
    【4】启动项目,发布到tomcat

    需要添加一个tomcat,需要本地安装tomcat8.

     

    注意:application context表示项目根路径。【这里修改为/】

     然后,页面访问,响应结果如下所示:

    3.1.2.2.基于springboot构建web项目

     1.使用idea的spring initialzr插件创建springboot项目

    设置项目坐标:

    添加依赖,选择web--->Spring web,并设置spring boot版本,如下所示:

    默认生成项目结构如下所示:

     2.对比springboot项目与spring-web项目的区别

      可以看到springboot是一个jar文件。并且提供统一的main启动入口。如下所示:

    package com.wf.demo.springbootdemo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class SpringBootDemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringBootDemoApplication.class, args);
        }
    
    }

    我们可以把Application类当成一个Controller,定义接口方法,如下所示:

    然后,启动main方法,浏览器访问:http://localhost:8080/test,响应结果如下所示:

     说明:

      使用spring boot开发web项目是如此的简单。【啥东西都不用配置】

     3.1.2.3.springboot再认识

      通过springboot使用demo,我们了解springboot到底是一个什么样的东西。

    它是一个约定优于配置,理念下的一个产品。

    1.内置tomcat容器

      我们看springboot项目的启动很简单,只需要运行main方法。当会把程序发布到容器中,它是如何实现呢?

    其实它是内置tomcat容器。从项目启动日志来看,springboot2.3.1版本,内置tomcat版本为9.0.36.

     

    它这个tomcat内置是如何实现的呢?

      我们可以查看pom.xml文件,有一个spring-boot-starter-web依赖jar包,

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    只要添加这个依赖,就能内置tomcat.内部tomcat依赖jar如下:
     <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
          <version>2.3.1.RELEASE</version>
          <scope>compile</scope>
        </dependency>
    spring boot默认支持四种容器布署,可以通过官方文档查看:

    https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/html/howto.html#howto-configure-webserver

    2.项目结构不同

    默认提供配置文件application.properties

    3.starter启动依赖
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
    <exclusion>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    </dependencies>

    3.1.3.springboot集成mybatis

      springboot是一个web层框架,如果需要调用dao层服务。还是需要集成orm框架【如:mybatis】

      当然,也可以使用spring jdbc组件。

    3.1.3.1.集成mybatis方案

    1.添加依赖

      如:mybatis-starter,数据库mysql驱动包

    <!--集成mybatis-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.2</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
    2.配置数据源
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.url=jdbc:mysql://localhost:3306/test_springboot?useUnicode=true&characterEncoding=utf8&serverTimezone=CTT
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    3.mybatis相关类定义

    可以基于反向工程生成,也使用在线生成工具,如下所示:

    https://www.cartoonai.com/

    这里自己编写:

    package com.wf.demo.springbootdemo.dao.mapper;
    
    import com.wf.demo.springbootdemo.dao.pojo.User;
    import org.apache.ibatis.annotations.Mapper;
    
    /**
     * @ClassName UserMapper
     * @Description 用户服务接口
     * @Author wf
     * @Date 2020/7/6 12:15
     * @Version 1.0
     */
    @Mapper
    public interface UserMapper {
        int insert(User user);
    }
    package com.wf.demo.springbootdemo.service;
    
    import com.wf.demo.springbootdemo.dao.pojo.User;
    
    /**
     * @ClassName IUserService
     * @Description 用户服务
     * @Author wf
     * @Date 2020/7/6 12:26
     * @Version 1.0
     */
    public interface IUserService {
        int insert(User user);
    }
    package com.wf.demo.springbootdemo.service;
    
    import com.wf.demo.springbootdemo.dao.mapper.UserMapper;
    import com.wf.demo.springbootdemo.dao.pojo.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    /**
     * @ClassName UserServiceImpl
     * @Description service实现
     * @Author wf
     * @Date 2020/7/6 12:27
     * @Version 1.0
     */
    @Service
    public class UserServiceImpl implements IUserService {
        @Autowired
        private UserMapper userMapper;
        @Override
        public int insert(User user) {
            return userMapper.insert(user);
        }
    }
    package com.wf.demo.springbootdemo.web;
    
    import com.wf.demo.springbootdemo.dao.pojo.User;
    import com.wf.demo.springbootdemo.service.IUserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @ClassName HelloController
     * @Description 测试controller
     * @Author wf
     * @Date 2020/7/6 11:27
     * @Version 1.0
     */
    @RestController
    public class HelloController {
        //配置文件注入
    //    @Value("Mic")
    //    private String name;
        @Autowired
        private IUserService userService;
    
        @GetMapping("hello")
        public String test(){
            User user = new User();
            user.setId(18);
            user.setName("MIc");
            userService.insert(user);
            return "success";
        }
    }
     4.resources下定义mapper.xml文件
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    
    <mapper namespace="com.wf.demo.springbootdemo.dao.mapper.UserMapper">
        <sql id="table_name">
            t_user
        </sql>
        <sql id="insert_columns">
            id,
            name
        </sql>
        <sql id="insert_values">
            #{id},#{name}
        </sql>
        <insert id="insert" keyProperty="id" useGeneratedKeys="true">
            insert into
            <include refid="table_name"/>
            (
            <include refid="insert_columns"/>
            )
            values
            (
            <include refid="insert_values"/>
            )
        </insert>
    </mapper>
    5.修改配置

    @Mapper是ibatis自定义注解,默认spring是无法扫描到自定义注解的。需要进行扫描处理。

    解决方案:

           可以基于spring中的扫描机制,在扫描注解时,去拦截@Mapper注解。

    所以,在程序启动入口进行mapper扫描处理,如下所示:

    @MapperScan("com.wf.demo.springbootdemo.dao.mapper")
    public class SpringBootDemoApplication {

    然后,配置mapper.xml文件路径:

    mybatis.mapper-locations=classpath:*Mapper.xml 

    然后,本地新建数据库test_springboot,并创建t_user表。

    CREATE TABLE `t_user` (

      `id` int(11) NOT NULL AUTO_INCREMENT,

      `name` varchar(255) DEFAULT NULL,

      PRIMARY KEY (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    然后,运行main,页面进行请求:

    http://localhost:8080/hello

    然后,查看数据库是否插入成功?如下所示:

    4.1.4.微服务的核心之springboot重新认识【下】

    时长:60min

    3.1.4.springboot与微服务  

      spring boot用于创建一个微服务项目,然后注册服务到注册中心。

    3.1.5.springboot的特性

    主要是四大核心机制

    》EnableAutoConfiguration 自动装配

    》starter启动依赖,开箱即用

    》Actuator监控

    》Spring boot cli【可以基于groovy脚本快速创建项目】

    3.1.6.spring注解驱动的发展过程

    3.1.6.1.spring framework注解驱动的发展历程

    1.spring1.X阶段

    IOC功能实现:bean注入,最初使用xml配置的方式,如下所示:

    <bean id="xxx" class="xxx"/>
    通过这种方式,就能将bean注入IOC容器,然后通过getBean方法从IOC容器中获取bean实例。

    这种基于xml配置的方式,有一个缺点,它会大量的依赖于配置文件

    下面在spring-mvc项目中,写一个测试示例:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
             http://www.springframework.org/schema/mvc http://www.springframework.org/schema/context/spring-mvc.xsd
             http://www.springframework.org/schema/aop http://www.springframework.org/schema/context/spring-aop.xsd"
           default-autowire="byName">
        <bean id="helloService" class="com.wf.service.HelloService"/>
    </beans>

    然后,定义Service类:

    package com.wf.service;
    
    /**
     * @ClassName HelloService
     * @Description service bean定义
     * @Author wf
     * @Date 2020/7/6 13:55
     * @Version 1.0
     */
    public class HelloService {
    }

    定义测试类:

    package com.wf.service;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * @ClassName HelloServiceDemo
     * @Description service bean获取测试
     * @Author wf
     * @Date 2020/7/6 14:03
     * @Version 1.0
     */
    public class HelloServiceDemo {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-bean.xml");
            HelloService service = context.getBean(HelloService.class);
            System.out.println(service);
        }
    }

    测试结果如下:

     说明:

      HelloService 这个bean注入成功,并能从ioc容器中取得实例。

      这里,使用xml配置方式,注入bean,管理bean,当配置变多,变得难以维护。

    2.Spring2.X阶段

      Spring2.5中引入注解驱动开发功能。如:

      @Component,@Service,@Autowired,@Controller,@RequestMapping...

    下面在spring-mvc项目中,以示例代码来说明,注解驱动开发的使用方式。

    【1】创建Service类
    package com.wf.service.annotation;
    
    import org.springframework.stereotype.Component;
    
    /**
     * @ClassName DemoServiceWithAnnotation
     * @Description 定义service bean
     * @Author wf
     * @Date 2020/7/6 14:16
     * @Version 1.0
     */
    @Component
    //@Service
    public class DemoServiceWithAnnotation {
    }

    说明:

      这里直接使用@Component注解注入bean,当然,也可以使用@Service注解。

    【2】xml中配置注解扫描包路径
    <!--注解扫描-->
    <context:component-scan base-package="com.wf.service"/>
    【3】测试bean实例获取
    package com.wf.service.annotation;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * @ClassName DemoServiceMain
     * @Description 测试bean获取
     * @Author wf
     * @Date 2020/7/6 14:21
     * @Version 1.0
     */
    public class DemoServiceMain {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-bean.xml");
            DemoServiceWithAnnotation bean = context.getBean(DemoServiceWithAnnotation.class);
            System.out.println(bean);
        }
    
    }

    测试结果如下所示:

     说明:

      这种注解驱动开发方式,只需要在xml中配置包扫描路径,即可扫描包下带注解的所有bean,并注入IOC容器。

      使用起来,方便很多。

    3.spring3.X阶段

      提供了取代xml配置文件的注解@Configuration,声明某个bean为配置类,可以以java代码的方式进行配置。

      这其实,是一种去xml化的发展趋势。

    下面以示例代码,来说明java代码进行配置的使用方法。

    【1】定义Service类
    package com.wf.service.demo1;
    
    /**
     * @ClassName DemoServiceWithConf
     * @Description bean 定义
     * @Author wf
     * @Date 2020/7/6 14:38
     * @Version 1.0
     */
    public class DemoServiceWithConf {
    }

    注意:

      这里没有声明注解。

    【2】定义bean配置类
    package com.wf.service.demo1;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @ClassName SpringConfiguration
     * @Description 配置类
     * @Author wf
     * @Date 2020/7/6 14:41
     * @Version 1.0
     */
    @Configuration
    public class SpringConfiguration {
        @Bean
        public DemoServiceWithConf demoServiceWithConf(){
            return new DemoServiceWithConf();
        }
    }
    【3】测试bean获取
    package com.wf.service.demo1;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    /**
     * @ClassName DemoServiceMain
     * @Description 测试bean获取
     * @Author wf
     * @Date 2020/7/6 14:21
     * @Version 1.0
     */
    public class DemoServiceMain {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
            DemoServiceWithConf bean = context.getBean(DemoServiceWithConf.class);
            System.out.println(bean);
        }
    
    }

    测试结果:

    说明:

      这里在配置类中,使用@Bean配置具体的某个bean。但是,如果我希望通过配置类,扫描所有的bean呢?应该怎么办呢?

      这就要结合@ComponentScan和@Service注解使用。

    代码修改如下:

    修改配置类,代码如下:

    package com.wf.service.demo1;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @ClassName SpringConfiguration
     * @Description 配置类
     * @Author wf
     * @Date 2020/7/6 14:41
     * @Version 1.0
     */
    @Configuration
    @ComponentScan("com.wf.service.demo1")
    public class SpringConfiguration {
    //    @Bean
    //    public DemoServiceWithConf demoServiceWithConf(){
    //        return new DemoServiceWithConf();
    //    }
    }

    定义Bean,添加@Service或@Component注解,如下所示:

    package com.wf.service.demo1;
    
    import org.springframework.stereotype.Service;
    
    /**
     * @ClassName DemoServiceWithConf
     * @Description bean 定义
     * @Author wf
     * @Date 2020/7/6 14:38
     * @Version 1.0
     */
    @Service
    public class DemoServiceWithConf {
    }

    然后,运行测试类:

     bean实例获取成功。

    【4】依赖注入bean如何进行配置

    service类定义:

    package com.wf.service.demo2;
    
    import com.wf.service.config.DemoServiceWithConf;
    
    /**
     * @ClassName DemoServiceWithDependency
     * @Description 关于依赖注入bean
     * @Author wf
     * @Date 2020/7/6 14:59
     * @Version 1.0
     */
    public class DemoServiceWithDependency {
        private DemoServiceWithConf demoServiceWithConf;
        //使用构造注入
        public DemoServiceWithDependency(DemoServiceWithConf demoServiceWithConf) {
            this.demoServiceWithConf = demoServiceWithConf;
        }
    
        public DemoServiceWithDependency() {
        }
    
        public void setDemoServiceWithConf(DemoServiceWithConf demoServiceWithConf) {
            this.demoServiceWithConf = demoServiceWithConf;
        }
    
        public DemoServiceWithConf getDemoServiceWithConf() {
            return demoServiceWithConf;
        }
    }

    配置类定义:

    package com.wf.service.demo2;
    
    import com.wf.service.config.DemoServiceWithConf;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @ClassName SpringConfiguration
     * @Description 配置类
     * @Author wf
     * @Date 2020/7/6 14:41
     * @Version 1.0
     */
    @Configuration
    @ComponentScan("com.wf.service.demo1")
    public class SpringConfiguration {
        @Bean
        public DemoServiceWithDependency demoServiceWithDependency(DemoServiceWithConf demoServiceWithConf){
            DemoServiceWithDependency demoServiceWithDependency = new DemoServiceWithDependency();
            demoServiceWithDependency.setDemoServiceWithConf(demoServiceWithConf);
            return demoServiceWithDependency;
        }
    }

    测试bean实例获取:

    package com.wf.service.demo2;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    /**
     * @ClassName DemoServiceMain
     * @Description 测试bean获取
     * @Author wf
     * @Date 2020/7/6 14:21
     * @Version 1.0
     */
    public class DemoServiceMain {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
            DemoServiceWithDependency bean = context.getBean(DemoServiceWithDependency.class);
            System.out.println(bean);
            System.out.println(bean.getDemoServiceWithConf());
        }
    
    }

    测试结果:

    总结:

      注解驱动的核心目的,是更加简单方便地装载bean.

    @ComponentScan,会扫描@Service,@Controller,@Repository注解。

    @Import注解,它相当于xml中<import resource="xxx"/>

    下面通过示例代码,来说明@Import注解的使用及功能:

    A.service类定义

    package com.wf.service.demo3;
    
    /**
     * @ClassName ImportService
     * @Description service bean定义
     * @Author wf
     * @Date 2020/7/6 15:20
     * @Version 1.0
     */
    public class ImportService {
    }

    B.配置类定义

    package com.wf.service.demo3;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @ClassName ImportConfiguration
     * @Description 配置类
     * @Author wf
     * @Date 2020/7/6 15:19
     * @Version 1.0
     */
    @Configuration
    public class ImportConfiguration {
        @Bean
    //    @Scope
        public ImportService  importService(){
            return new ImportService();
        }
    }

    【3】测试bean获取

    package com.wf.service.demo3;
    
    import com.wf.service.demo2.SpringConfiguration;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    /**
     * @ClassName DemoServiceMain
     * @Description 测试bean获取
     * @Author wf
     * @Date 2020/7/6 14:21
     * @Version 1.0
     */
    public class ImportServiceMain {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
            ImportService bean = context.getBean(ImportService.class);
            System.out.println(bean);
        }
    
    }

    注意:

      ImportService是在自己的配置类中装配的,而这里使用springConfiguraion配置类加载。所以,是获取不到bean的。

      为什么要用SpringConfiguration配置类来加载呢?

      因为一般项目中,都会只用一个总的配置类来加载所有的bean,而不会对于每个配置类都自己来加载。

    这里有两种解决方案:

    传参多个配置类,如下所示:

     》合并配置到总的配置类中,如下所示:

    然后,基于总的配置类来加载:

    package com.wf.service.demo3;
    
    import com.wf.service.demo2.SpringConfiguration;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    /**
     * @ClassName DemoServiceMain
     * @Description 测试bean获取
     * @Author wf
     * @Date 2020/7/6 14:21
     * @Version 1.0
     */
    public class ImportServiceMain {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
            ImportService bean = context.getBean(ImportService.class);
            System.out.println(bean);
        }
    
    }

    测试结果:

    Enable模块驱动

      基于@EnableXXX模块驱动注解,如下所示:

     通过注解驱动的发展,可以很方便地管理bean.如果我们希望在spring3.x模块下,集成redis需要如何做呢?

    》创建一个配置类

    》@Bean注解方式来声明一个bean【这个bean是一个第三方定义bean】

      这个集成过程,还是比较复杂。spring索性就提供了Enable模块驱动。

      使用@EnableXXX启动一个模块,把相关组件所需bean自动装配到ioc容器中。

    下面通过,集成定时器,通过示例代码来说明:

    A.xml中配置定时器bean

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:task="http://www.springframework.org/schema/task"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
             http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd"
           default-autowire="byName">
    
        <!--注解扫描-->
        <context:component-scan base-package="com.wf.service"/>
    
        <task:annotation-driven scheduler="scheduler"/>
        <!--通过开启注解驱动去扫描定时器任务执行-->
        <task:scheduler id="scheduler" pool-size="5"/>
    </beans>

    注意:

      需要task的schema,及注解开启。

    B.创建定时器bean

    package com.wf.service.task;
    
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    import java.util.Date;
    
    /**
     * @ClassName TaskService
     * @Description 定时器bean
     * @Author wf
     * @Date 2020/7/6 16:20
     * @Version 1.0
     */
    @Service
    public class TaskService {
        @Scheduled(fixedRate = 3000)//每隔3秒钟执行一次
        public void reportCurrentTime(){
            System.out.println("current time:"+new Date());
        }
    }

    C.测试bean实例获取 

    package com.wf.service.task;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * @ClassName TaskMain
     * @Description 测试bean获取
     * @Author wf
     * @Date 2020/7/6 16:23
     * @Version 1.0
     */
    public class TaskMain {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-task.xml");
            TaskService bean = context.getBean(TaskService.class);
            System.out.println(bean);
        }
    }

    测试结果如下:

    下面使用Enable式配置类,实现定时器功能:

    A.创建配置类

    package com.wf.service.enabletask;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.EnableScheduling;
    
    /**
     * @ClassName TaskConfiguration
     * @Description 定时器配置类
     * @Author wf
     * @Date 2020/7/6 16:45
     * @Version 1.0
     */
    @ComponentScan("com.wf.service.enabletask")
    @EnableScheduling
    @Configuration
    public class TaskConfiguration {
    }

    注意:

      这里使用@EnableScheduling注解,开启定时器模块。

    B.创建定时器bean类

    package com.wf.service.enabletask;
    
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    import java.util.Date;
    
    /**
     * @ClassName TaskService2
     * @Description service bean类
     * @Author wf
     * @Date 2020/7/6 16:46
     * @Version 1.0
     */
    @Service
    public class TaskService2 {
        @Scheduled(fixedRate = 3000)//每隔3秒钟执行一次
        public void reportCurrentTime(){
            System.out.println("current time:"+new Date());
        }
    }

    C.合并配置类到总配置类中

     D.基于注解驱动方式获取bean实例

    package com.wf.service.enabletask;
    
    import com.wf.service.SpringConfiguration;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    /**
     * @ClassName TaskMain
     * @Description 测试bean获取
     * @Author wf
     * @Date 2020/7/6 16:23
     * @Version 1.0
     */
    public class TaskMain {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
            TaskService2 bean = context.getBean(TaskService2.class);
            System.out.println(bean);
        }
    }

    得到一样的结果。

    这种Enable模块驱动是如何实现的呢?下面来跟踪下源码,分析实现原理:

    其实是AnnotationDrivenBeanDefinitionParser中parse方法在解析定时器配置。

    下面debug调试xml方式定时器实现。先在AnnotationDrivenBeanDefinitionParser中设置断点如下所示:

     当dubug启动main方法时,直接进入断点处。

    可以看到首先会解析xml中配置的task:annotation-driven标签。这里获得mode为proxy【代理】,进入else分支

    下面来看下Enable启动定时器的实现原理:

    引入SchedulingConfiguration定时器配置类。

    实现 ScheduledAnnotationBeanPostProcessor装配bean,两则实现方式是差不多的。

  • 相关阅读:
    zookeeper与activemq最新存储replicatedLevelDB整合
    MySQL分表的3种方法
    mycat 从入门到放弃 (转)
    centos 7 忘记密码
    java内存溢出的情况解决方法
    跨域问题的产生及解决方法
    一次jvm调优过程
    2019年总结
    Jenkinsfile与Json的转换
    DevOps平台
  • 原文地址:https://www.cnblogs.com/wfdespace/p/13232070.html
Copyright © 2011-2022 走看看