Spring组件添加(注册组件)

Spring需要使用的组件配置pom.xml

0.注解添加组件的四种方法

  • 1)@Bean: [导入第三方的类或包的组件],比如Person为第三方的类, 需要在我们的IOC容器中使用
  • 2)包扫描+组件的标注注解(@ComponentScan: @Controller, @Service @Repository @ Component),一般是针对 我们自己写的类,使用这个
  • 3)@Import:[快速给容器导入一个组件] 注意:@Bean有点简单
    3-a)@Import(要导入到容器中的组件):容器会自动注册这个组件,bean 的 id为全类名
    3-b)ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
    3-c)ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器, 所有Bean的注册可以使用BeanDifinitionRegistry
    写JamesImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口即可
  • 4)使用Spring提供的FactoryBean进行注册

1.基于XML配置

使用bean标签注册组件Person.java(配置文件beans.xml参考):

    
        
        
    

测试类MainTest1.java

    public static void main(String args[]){
        //把beans.xml的类加载到容器
        ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
        //从容器中获取bean
        Person person = (Person) app.getBean("person");

        System.out.println(person);
    }

结果:

Person [name=wz, age=19]

2.@Configuration + @Bean

配置类MainConfig等价于配置文件beans.xml:

//配置类====配置文件
@Configuration
public class MainConfig {
    //给容器中注册一个bean, 类型为返回值的类型,
    @Bean("abcPerson")
//    @Bean
    public Person person01(){
        return new Person("wz",20);
    }
}

测试类MainTest2.java

public class MainTest2 {
    public static void main(String args[]){
        ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);

        //从容器中获取bean
        Person person = (Person) app.getBean("abcPerson");

        System.out.println(person);

        String[] namesForBean = app.getBeanNamesForType(Person.class);
        for(String name:namesForBean){
            System.out.println(name);
        }
    }
}

结果:

Person [name=wz, age=20]
abcPerson

2.1 @Scope (单实例、多实例)

配置类Ch3MainConfig.java

@Configuration
public class Ch3MainConfig {
    //给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
    /*
     * prototype:多实例: IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象, 而是每次获取的时候才会调用方法创建对象
     * singleton:单实例(默认):IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿(大Map.get)的同一个bean
     * request: 主要针对web应用, 递交一次请求创建一个实例
     * session:同一个session创建一个实例
     */
    @Scope("prototype")
    @Bean
    public Person person(){
        return new Person("wz",20);
    }
}

Scope测试类Ch3Test.java

public class Ch3Test {
    @Test
    public void test01(){
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch3MainConfig.class);


        String[] names = app.getBeanDefinitionNames();

        for(String name:names){
            System.out.println(name);
        }
        //从容器中分别取两次person实例, 看是否为同一个bean
        Object bean1 = app.getBean("person");
        Object bean2 = app.getBean("person");
        System.out.println(bean1 == bean2);
    }
}

2.2 @lazy (控制单例bean什么时候创建对象)

lazy配置类Ch4MainConfig.java

@Configuration
public class Ch4MainConfig {
    //给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
    /*
     * 懒加载: 主要针对单实例bean:默认在容器启动的时候创建对象
     * 懒加载:容器启动时候不创建对象, 仅当第一次使用(获取)bean的时候才创建被初始化
     */
    @Lazy
    @Bean
    public Person person(){
        System.out.println("给容器中添加person.......");
        return new Person("james",20);
    }
}

lazy测试类Ch4Test.java

public class Ch4Test {
    @Test
    public void test01(){
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch4MainConfig.class);

        System.out.println("IOC容器创建完成........");
        app.getBean("person");//执行获取的时候才创建并初始化bean

    }
}

2.3 @Conditional

Conditional配置类Ch5MainConfig.java

@Configuration
public class Ch5MainConfig {
    @Bean("person")
    public Person person(){
        System.out.println("给容器中添加person.......");
        return new Person("person",20);
    }

    @Conditional(WinCondition.class)
    @Bean("lison")
    public Person lison(){
        System.out.println("给容器中添加lison.......");
        return new Person("Lison",58);
    }
    @Conditional(LinCondition.class)
    @Bean("james")//bean在容器中的ID为james, IOC容器MAP,  map.put("id",value)
    public Person james(){
        System.out.println("给容器中添加james.......");
        return new Person("james",20);
    }
}

判断操作系统是否是Windows的类WinCondition.java

public class WinCondition implements Condition {
    /*
     *ConditionContext: 判断条件可以使用的上下文(环境)
     *AnnotatedTypeMetadata: 注解的信息
     *
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // TODO 是否为WINDOW系统
        //能获取到IOC容器正在使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //获取当前环境变量(包括我们操作系统是WIN还是LINUX??)
        Environment environment = context.getEnvironment();
        String os_name = environment.getProperty("os.name");
        if(os_name.contains("Windows")){
            return true;
        }
        return false;
    }
}

Conditional测试类Ch5Test.java

public class Ch5Test {
    @Test
    public void test01(){
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch5MainConfig.class);

        System.out.println("IOC容器创建完成........");
    }
}

3.@ComponentScan

整个ComponentScan的各种用法参考ch2
ComponentScan的测试类Ch2Test.java
配置类Cap2MainConfig.java
作用:指定要扫描的包,并且可以定制扫描时的过滤规则

  • useDefaultFilters默认是true,扫描所有组件,要改成false,使用自定义扫描范围
  • @ComponentScan value:指定要扫描的包
  • excludeFilters = Filter[] 指定扫描的时候按照什么规则排除那些组件
  • includeFilters = Filter[] 指定扫描的时候只需要包含哪些组件
  • 扫描规则:
    FilterType.ANNOTATION:按照注解
    FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按OrderController.class类型
    FilterType.ASPECTJ:使用ASPECTJ表达式
    FilterType.REGEX:使用正则指定
    FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口,参考WzTypeFilter.java
@Configuration
//@Controller  @Service  @Repository  @Component

//@ComponentScan(value="com.wangzhen.ch2")

//@ComponentScan(value="com.wangzhen.ch2", includeFilters={
//        @ComponentScan.Filter(type=FilterType.ANNOTATION, classes={Controller.class})
//}, useDefaultFilters=false)

//@ComponentScan(value="com.wangzhen.ch2", excludeFilters={
//        @ComponentScan.Filter(type=FilterType.ANNOTATION, classes={Controller.class})
//}, useDefaultFilters=true)

//@ComponentScan(value="com.wangzhen.ch2", includeFilters={
//        @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, classes={OrderController.class})
//}, useDefaultFilters=false)

@ComponentScan(value="com.wangzhen.ch2", includeFilters={
        @ComponentScan.Filter(type=FilterType.CUSTOM, classes={WzTypeFilter.class})
}, useDefaultFilters=false)


public class Cap2MainConfig {
    //给容器中注册一个bean, 类型为返回值的类型,
    @Bean
    public Person person01(){
        return new Person("james",20);
    }
}

4.@Import

Import配置类Ch6MainConfig.java

@Configuration
@Import(value = { Dog.class, Cat.class, JamesImportSelector.class,JamesImportBeanDefinitionRegistrar.class })

public class Ch6MainConfig {
    /*
     * 给容器中注册组件的方式
     * 1,@Bean: [导入第三方的类或包的组件],比如Person为第三方的类, 需要在我们的IOC容器中使用
     * 2,包扫描+组件的标注注解(@ComponentScan:  @Controller, @Service  @Repository  @ Component),一般是针对 我们自己写的类,使用这个
     * 3,@Import:[快速给容器导入一个组件] 注意:@Bean有点简单
     *      a,@Import(要导入到容器中的组件):容器会自动注册这个组件,bean 的 id为全类名
     *      b,ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
     *      c,ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器, 所有Bean的注册可以使用BeanDifinitionRegistry
     *          写JamesImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口即可
     * 4,使用Spring提供的FactoryBean(工厂bean)进行注册
     *
     *
     */
    //容器启动时初始化person的bean实例
    @Bean("person")
    public Person persond(){
        System.out.println("aaaaaaaaaaaa");
        return new Person("james",20);
    }
    //@Bean("person1")
    public Person persona(int a){
        System.out.println("bbbbbbbbbbb");
        return new Person("james",20);
    }
    @Bean
    public JamesFactoryBean jamesFactoryBean(){
        return new JamesFactoryBean();
    }
}

实现ImportSelector接口注册组件

public class JamesImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata){
        //返回全类名的bean
        //return null; 不要返回null
        // return new String[]{};
        return new String[]{"com.wangzhen.ch6.bean.Fish","com.wangzhen.ch6.bean.Tiger"};
    }
}

实现接口ImportBeanDefinitionRegistrar注册组件

public class JamesImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /*
     *AnnotationMetadata:当前类的注解信息
     *BeanDefinitionRegistry:BeanDefinition注册类
     *    把所有需要添加到容器中的bean加入;
     *    @Scope
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean bean1 = registry.containsBeanDefinition("com.wangzhen.ch6.bean.Dog");
        boolean bean2 = registry.containsBeanDefinition("com.wangzhen.ch6.bean.Cat");
        //如果Dog和Cat同时存在于我们IOC容器中,那么创建Pig类, 加入到容器
        //对于我们要注册的bean, 给bean进行封装,
        if(bean1 && bean2){
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
            registry.registerBeanDefinition("pig", beanDefinition);
        }
    }
}

Import测试类

public class Ch6Test {
    @Test
    public void test01() {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch6MainConfig.class);

        System.out.println("IOC容器创建完成........");
        String[] beanDefinitionNames = app.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println(name);
        }
    }
}

5.FactoryBean

FactoryBean配置类Ch6MainConfig.java

    @Bean
    public JamesFactoryBean jamesFactoryBean(){
        return new JamesFactoryBean();
    }

JamesFactoryBean类实现FactoryBean接口

public class JamesFactoryBean implements FactoryBean {

    @Override
    public Monkey getObject() throws Exception {
        // TODO Auto-generated method stub
        return new Monkey();
    }

    @Override
    public Class getObjectType() {
        // TODO Auto-generated method stub
        return Monkey.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

FactoryBean测试类

public class Ch6Test {
    @Test
    public void test01() {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch6MainConfig.class);

        System.out.println("IOC容器创建完成........");

        Object bean1 = app.getBean("jamesFactoryBean");
        Object bean2 = app.getBean("jamesFactoryBean");//取Money
        System.out.println("bean1的类型=" + bean1.getClass());
        System.out.println(bean1 == bean2);

        Object bean3 = app.getBean("&jamesFactoryBean");
        System.out.println("bean3的类型=" + bean3.getClass());
  • FactoryBean注册组件的源码解析后可知
    容器调用getObject()返回对象,把对象放到容器中;
    getObjectType()返回对象类型
    isSingleton()是否单例进行控制
    a)默认获取到的是工厂bean调用getObject创建的对象
    b)要获取工厂Bean本身,需要在id前加个 &jamesFactoryBean

参考

  • 1)享学课堂James老师笔记

你可能感兴趣的:(Spring组件添加(注册组件))