SpringIOC容器底层注解使用

w'wSpringIOC容器底层注解使用

  1. xml配置文件的形式VS配置类的形式

    1. 基于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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 定义一个 Bean 的信息 --> <bean id="car" class="com.demo.compent.Car"></bean> </beans>
      //去容器中读取bean
      public static void main( String[] args ) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); System.out.println(ctx.getBean("person")); }
    2. 基于读取配置类的形式定义bean的信息

      @Configuration
      public class MainConfig{
         @Bean
         public Person person(){
             return new Person();
        }
      }
      //去容器中读取Bean的信息(传入配置类)
      public static void main(String[] args){
         AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(MainConfig.class);
         System.out.println(ctx.getBean("person"));
      }
      //注意:通过@Bean的形式使用的话,bean的默认名称是方法名,若@Bean(Value="bean的名称"),那么bean的名称就是指定的
  2. 在配置类上写@ComponentScan注解来进行扫描

    @Configuration
    @ComponentScan(basePackage={"com.dome.testcompentscan"})
    public class MainConfig{

    }
  3. 排除用法excludeFilters:排除@Controller注解的和TestService的

    @Configuration
    @ComponentScan(basePackage={"com.demo.testcompentscan"})
    @ComponentScan.Filter(type=FilterType.ANNOTATION,value={Controller.class})
    @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,value={TestService.class})
    public class MainConfig{
       
    }
  4. 包含用法includeFilters:若使用包含的用法,需要把useDefaultFilters属性设置为false(true表示全部扫描)

    @Configuration
    @ComponentScan(basePackage={"com.demo.testcompentscan"},includeFilters={@ComponentScan.Filter(type=FilterType.ANNOTATION,value={Controller.class,Service.class})},userDefaultFilters=fasle)
    public class MainConfig{}
  5. 配置bean的作用域对象

    1. 在不指定@Scope的情况下,所有的bean都是单例的bean,而且是饿汉加载(容器启动实例就创建好了)

      @Bean
      public Person person(){
         return new Person();
      }
    2. 指定@Scope为prototype表示为多实例的,而且还是懒汉模式加载(IOC容器启动的时候,并不会创建对象,而是在第一次使用时才创建)

      @Bean
      @Scope(value="prototype")
      Public Person person(){
      	return new Person();
      }
    3. @Scope指定的作用域取值

      1. Singleton单例模式(默认)

      2. prototype多实例的

      3. request同一次请求

      4. session同一个会话级别

  6. Bean的懒加载@Lazy

    @Bean
    //主要针对单实例的bean的容器启动的时候,不创建对象,在第一次使用时才会创建该对象
    @Lazy
    public Person person(){
        return new Person
    }
  7. @Conditional进行条件判断等

    //场景:有两个组件TestAspect和TestLog,其中TestLog组件是依赖于TestAspect的组件
    //应用:自己创建一个TestCondition的类实现Condition接口
    public class TestCondition implements Condition{
        @Override
        public Boolean matches(ConditionContext context,AnnotatedTypeMetadata medata){
           // 判读容器中是否有TestAspect的组件
            if(context.getBeanFactory().containsBean("TestAspect")){
                return ture;
            }
            return false;
        }
    }
    public class MainConfig{
       @Bean
       public TestAspect testAspect(){
           return new TestAspect();
      }
       //当且容器中有testAspect的组件,那么testLog才会被实例化
       @Bean
       @Condition(value=TestCondition.class)
       public TestLog testLog(){
           return new TestLog(;
      }
    }
  8. 往IOC容器中添加组件的方式

    1. 通过@CompentScan+@Controller@Service@Respository@Conpent

    2. 通过@Bean的方式来导入组件:适用于导入第三方组件的类

    3. 通过@Import来导入组件,导入 组件的id为类的全类名路径

      @Configuration
      @Import(value={Person.class,Car.class})
      public class MainConfig{}
      1. 通过@Import的ImportSelector类实现组件 的导入

        //导入组件的id为类的全路径
        public class TestImportSelector implements ImportSelector{
           //可以获取导入类的注解信息
           @Override
           public String[] selectImports(AnnotationMetadata importingClassMetadata){
               return new String[]{"com.demo。testimport.compent.Dog"};
          }
        }
        @Configuration
        @Import(value={Person.class,Car.class,TestImportSelector.class})
        public class MainConfig{}
      2. 通过Import的ImportBeanDefinitionRegister导入组件

        //可以指定Bean的名称
        public class TestBeanDenifitionRegister implements ImportBeanDefinitionRegister{
           @Override
           public void registerBeanDefinitionRegister(AnnotationMetadata importingClassMetadata,BeanDenifitionRegistry registry){
               //创建一个bean定义对象
               RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(Cat.class);
               //把bean定义对象导入容器中
               registry.registerBeanDefinition("Cat",rootBeanDefinition);
          }
        }
        @Configuration
        @Import(value={Person.class,Car.class,TestImportSelector.class,TestBeanDefinitionRegister.class})
        public class MainConfig{}
    4. 通过实现FactoryBean接口来实现注册组件

      public class CarFactoryBean implements FactoryBean<Car>{
         //返回Bean对象
         @Override
         public Car getObject() throws Exception{
             return new Car();
        }
         //返回bean的类型
         @Override
         public Class<?> getObjectType(){
             return Car.class;
        }
         //是否是单例模式
         @Override
         public Boolean isSingleton(){
             return true;
        }
      }
  9. Bean的初始化方法和销毁方法

    1. 什么是bean的生命周期

      bean的创建----->初始化----->销毁方法

      //有容器管理bean的生命周期,我们可以自己指定bean的初始化方法和销毁方法
      @Configuration
      public class MainConfig{
          //指定bean 生命周期的初始化方法和销毁方法
          @Bean(initMethod="init",destoryMethod="destory")
          public Car car{
              reutrn new Car();
          }
      }
      //针对于单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用bean的销毁方法 
      //针对多实例的bean的话,容器再启动的时候,Bean是不会被创建的,而且bean的销毁不受IOC容器的管理
    2. 通过InitalizingBean和DisposableBean的两个接口实现

      @Componment
      public class Person implements InitalizingBeab,DisposableBean{
         public Person(){
             System.out.println("Person的构造方法")
        }
         @Override
         public void destory() throws Exception{
             System.out.pringln(DisposableBean的destory()方法)
        }
         @Override
         public void afterPropertiesSet() throws Exception{
             System.out.rintln("InitialzingBean的afterPropertiesSet()方法")
        }
      }
    3. 通过Spring的BeanPostProcessor的bean的后置处理器会拦截所有bean的创建过程

      public class TestBeanPostProcessor implements BeanPostPrecessor{
         //在init方法调用之前
         @Override
         public Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException{
             System.out.pringln("TestBeanPostProcessor...postProcessBeaforeInitialization:"+beanName);
        }
         //在init方法调用之后
         @Override
         public Object postProcessAfterInitialization(Object bean,String beanName) throws BeansException{
             System.out.println("testBeanPostPrecessor...postProcessorAfterInitialization:"+beanName);
        }
      }
      //BeanPostProcessor的执行时间
      populateBean(beanName,mbd,instanceWrapper);
      initializeBeanBean{
         applyBeanPostProcessorBeforeInitialization();
      invokeInitMethods{
          isInitMethod{
                        isInitializingBean.afterPropertiesSet
      自定义的init方法
                 
          }
          applyBeanPostProcessorsAfterInitialization()方法
      }

      }
    4. 通过@Value+@PropertySource来给组件赋值

      public class Person{
         //通过普通的方式
         @Value("司马")
         private String firstName;
         //spel方式来赋值
         @Value("#{28-8}")
         private Integer age;
         //通过读取外配置文件的值
         @Value("${person.lastName}")
         private String lastName;
      }
      @Configuration
      //指定外部文件的位置
      @PropertySource(value={"classpath:person.properties"})
      public class MianConfig{
         @Bean
         public Person person(){
             return new Person();
        }
      }
  10. 自动装配

    1. @Autowired的使用

      1. 自动注入

        @Repository
        public class TestDao{}
        @Service
        public class TestService{
            @Autowired
            private TestDao testDao;
        }
      2. 自动注入结论

        1. 自动装配首先是按照类型进行装配,若在IOC容器中发现了多个相同类型的组件,那么就按照属性名称进行装配

          @AutoWired
          private TestDao testDao;
          //比如上面代码:如果容器中有两个TestDao类型的组件,一个叫做testDao,一个叫做testDao2,那么我们通过@Autowired来修饰的属性名称是testDao,那么就加载容器的testDao组件,如果属性名称是testDao2,那么容器就加载的是testDao2组件
        2. 假设需要指定特定的组件来进行装配,我们可以通过使用@Qualifier("testDao")来指定装配的组件,或者在配置类上的@Bean加上@Primary注解

          @Autowired
          @Qualifier("testDao")
          public TestDao testDao2;
          
        3. 假设容器中没有testDao也没有testDao2,那么在装配时就会抛出异常No qualifying bean of type'com.demo.testautowired.TestDao'available,若不想抛出异常,就需要指定required为false的时候就可以了

          @Autowired(required=false)
          @Qualifier("testDao")
          private TestDao testDao2;
        4. @Resource(JSR250规范):功能和Autowired差不多一样,但是不支持@Primary和@Qualifier的支持

        5. @Inject(JSR330规范):需要导入JAR包依赖。功能支持@Primary,但是没有Required=false的功能

          <dependency>
             <groupId>javax.inject</groupId>      <artifactId>javax.inject</artifactId>
          <version>1</version>
          </dependency>
          
          
        6. 使用Autowired可以标注在方法上

          1. 标注在set方法上

          2. 标注在构造方法上

          3. 标注在配置类的入参中

      3. 我们自己的组件如何使用SpringIOC底层组件

        //加入我们自己的组件组要使用ApplicationContext等,我们可以通过实现XXXAwire接口来实现
        @Component
        public class TestComponent implements ApplicationContextAware,BeanNameAware{
           private ApplicationContext applicationContext;
           @Override
           public void setBeanName(String name){
               System.out.println("current beab name is:【"+name+"】")
          }
           @Override
           public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
               this.applicationContext=applicationContext;
          }
        }
      4.  

       

     

     

     

     

原文地址:https://www.cnblogs.com/juddy/p/14395634.html