spring注解驱动开发(一):spring中的@Configuration、@Bean、@ComponentScan注解

在spring中如何使用注解的方式?使用注解方式比XML配置文件方式对比有什么优点?本系列文章是对注解开发基本使用,作为系列文章的第一篇,本篇将来说明@Configuration、@Bean和@ComponentScan注解的使用。

0. 准备工作

  1. 使用IDEA新建一个Maven工程。
  2. 在maven工程导入依赖。
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
pom.xml 添加依赖

1. 配置文件方式

    1.1 配置文件开发步骤:以从容器中获得User对象为例。

  1. 定义实体类User。
  2. 定义一个xml配置文件,将User的属性值赋值并注入到容器中。
  3. 定义测试方法,从容器中获得对象,并打印在控制台

    1.2 代码示例。

        1. 定义实体类User。

public class User {

    private String username;
    private Integer age;

    public User() {
    }

    public User(String username, Integer age) {
        this.username = username;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}
User.java

        2. 定义一个xml配置文件,将User的属性值赋值并注入到容器中。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <beans>
        <bean id="user" class="org.gwsix.ch01.bean.User">
            <property name="username" value="张三"/>
            <property name="age" value="1"/>
        </bean>

    </beans>
</beans>
beans.xml

         3. 定义测试方法,从容器中获得对象,并打印在控制台

    @Test
    public void testXML() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/org/gwsix/ch01/beans.xml");
        User user = (User)applicationContext.getBean("user");
        System.out.println(user);
    }
Main.java

        执行testXml()方法,控制台打印下面信息,我们成功将bean成功注入到容器中,并可以在容器中获得bean相关信息。

User{username='张三', age=1}

2. 注解方式

    2.1 注解开发步骤:以从容器中获得User对象为例。

  1. 定义实体类User。
  2. 定义一个配置类,通过配置类将bean注入到容器中。
  3. 定义测试方法,从容器中获得对象,并打印在控制台

    2.2 代码示例。

        1. 定义实体类User,和xml配置文件的实体类一致。
        2. 定义配置类

@Configuration //标识配置类,相当于beans.xml中的<beans>标签
public class MainConfig {
    /**
     * 默认是以方法名作为注册进容器bean的名字,下面三种均可改变容器的bean的名
     *   methodName
     *   @Bean(value = "user")
     *   @Bean(name = "user")
     * @return
     */
    @Bean(value = "user") //给容器中注册bean,相当于<bean>,默认方法的名是注入bean名称
    public User user(){
        return new User("李四",18);
    }
}
MainConfig.java

        3. 定义测试方法,从容器中获得对象,并打印在控制台

    @Test
    public void testConfig() {
        ApplicationContext applicationContext = new  AnnotationConfigApplicationContext(MainConfig.class);
        User user = (User)applicationContext.getBean("user");
        System.out.println(user);
        //getBeanDefinitionNames() 获得容器中所有输入类的名称
        System.out.println("---容器中的组件---");
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames){
            System.out.println(name);
        }
    }
View Code

       注意:在注解版本中使用的是AnnotationConfigApplicationContext。

                   String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();获得容器中的bean。

       执行textAnnotation(),控制台输出下面内容,说明bean注册到容器中,并可以获取到。

User{username='李四', age=18}
---容器中的组件---
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
user

3. 注解使用小结  

    1)使用@Configuration向容器注册配置类,这个注解修饰的类类似于xml配置中的<beans>标签。

    2)使用@Bean向容器中注册组件,new一个对象返回,类似于<bean>标签,@Bean默认是以方法名作为bean注册到容器,另外使用注解的name或者value属性可 以修改注入到容器的值@Bean(name="user1")\@Bean(name="user1"),查看源码可以看到value其实是name的提个别名。

    3)使用注解版本的AnnotationApplicationContation类来初始化容器,参数是使用@Configurtion注解修饰的类。

    4)可以使用applicationContext.getBeanDefinitionNames()方法获得容器中所有的bean名称。

4. @ComponentScan注解的使用

    @ComponentScan注解功能和<context:component-scan base-package="org.gwsix.ch01"/>作用一样,扫描指定路径下的包。

  4.1 简单使用@ComponentScan注解

    1.新建UserController、UserService和UserDao分别用@Controller、@Service和@Repository注解,代码如下:

@Controller
public class UserController {
}

@Service
public class UserService {
}

@Repository
public class UserDao {
}
新建UserController、UserService和UserDao类

    2.修改配置类

@Configuration //标识配置类,相当于beans.xml中的<beans>标签
@ComponentScan(value = {"org.gwsix.ch01"})
public class MainConfig {
    /**
     * 默认是以方法名作为注册进容器bean的名字,下面三种均可改变容器的bean的名
     *   methodName
     *   @Bean(value = "user")
     *   @Bean(name = "user")
     * @return
     */
    @Bean(value = "user") //给容器中注册bean,相当于<bean>,默认方法的名是注入bean名称
    public User user(){
        return new User("李四",18);
    }
}
配置类新增@ConponentScan注解

    3.添加测试方法,查看容器中的bena

    @Test
    public void testComponentScan() {
        ApplicationContext applicationContext = new  AnnotationConfigApplicationContext(MainConfig.class);
        System.out.println("---容器中的组件---");
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames){
            System.out.println(name);
        }
    }
测试方法

    执行测试方法,控制台输出下面信息表示新增的类进入到容器中。

---容器中的组件---
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
userController
userDao
userService
user

  4.2 详解@ComponentScan注解

@ComponentScan(value = "org.gwsix.ch01",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class, Service.class})},
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class, Service.class})},
        useDefaultFilters = false)

    @ComponentScan参数详解

        userDefaultFilters=false//禁用以前默认的扫描规则,默认值是true,功能对比配置文件中use-default-filters="false"

        excludeFilters={}排除扫描的规则,这个会比includeFilters 后执行,功能对比配置文件中

             <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:exclude-filter>

       includeFilters = {}使用扫描的规则,如果使用这个,需要把useDefaultFilters = false,功能对比配置文件中

           <context:include-filter type="annotation" expression="org.springframework.stereotype.S"/></context:component-scan>

    FilterType详解,这是一个枚举不同的枚举值代表不同的过滤规则

       FilterType.ANNOTATION 按照注解方式

       FilterType.ASSIGNABLE_TYPE, 按照给定的类型,本类和子类,@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE ,value = {UserDao.class}),新建UserDaoImpl类继承UserDao。

       FilterType.ASPECTJ, 使用aspectj表达式,不常用

       FilterType.REGEX,使用正则表达式

       FilterType.CUSTOM;自定义规则,包含过滤指定的规则

    FilterType.CUSTOM;自定义规则

public class MyTypeFilter implements TypeFilter {
    //metadataReader 当前扫描类的信息
    //metadataReaderFactory 可以获取其他类的信息
    @Override //true 匹配成功,false匹配失败
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)  {
        //获取当前类的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前类的信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获得当前类的资源信息 路径
        Resource resource = metadataReader.getResource();
        String className = classMetadata.getClassName();
        System.out.println("当前类-->"+className);
        //类名包含er,注入到bean,可以将@Service去掉
        if(className.contains("er"))
            return true;
        return false;
    }
}
自定义过滤规则,将bean名带er注册到容器

        最后配置类@ComponentScan的参数如下

@ComponentScan(value = "org.gwsix.ch01",
        //excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class})},
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class, Service.class}),
                          @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE ,value = {UserDao.class}),
                          @ComponentScan.Filter(type=FilterType.CUSTOM,value = {MyTypeFilter.class})
        },
        useDefaultFilters = false)

        控制台输出结果

当前类-->org.gwsix.ch01.bean.User
当前类-->org.gwsix.ch01.config.MyTypeFilter
三月 22, 2019 10:34:47 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
信息: Overriding bean definition for bean 'user' with a different definition: replacing [Generic bean: class [org.gwsix.ch01.bean.User]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [F:\spring\spring-bean-configuration\target\classes\org\gwsix\ch01\bean\User.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=mainConfig; factoryMethodName=user; initMethodName=null; destroyMethodName=(inferred); defined in org.gwsix.ch01.config.MainConfig]
---容器中的组件---
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
user
myTypeFilter
userController
userDao
userDaoImpl
userService 

5. @ComponentScan使用小结

    1)自定义过滤规则,需要类是实现TypeFilter,重写接口得方法。

    2)排除规则是最后执行的,excludeFilters比includeFilters后执行 

posted @ 2019-03-21 16:46  i孤独行者  阅读(351)  评论(0)    收藏  举报