@Configuration和@Bean 
@Configuration 注解表示吧一个类声明为一个配置类 
@Bean 注解相当于在容器中注册一个 bean 
 
新建一个Person类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package  com.szx.bean;public  class  Person      String name;     Integer age;     @Override      public  String toString ()           return  "Person{"  +                 "name='"  + name + '\''  +                 ", age="  + age +                 '}' ;     }     public  String getName ()           return  name;     }     public  void  setName (String name)           this .name = name;     }     public  Integer getAge ()           return  age;     }     public  void  setAge (Integer age)           this .age = age;     }     public  Person (String name, Integer age)           this .name = name;         this .age = age;     }     public  Person ()       } } 
通过配置类注册一个Person bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package  com.szx.config;import  com.szx.bean.Person;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Configuration;@Configuration public  class  BeanConfig                     @Bean("person01")      public  Person person ()          return  new  Person("张三" ,16 );     } } 
实例化 AnnotationConfigApplicationContext 得到 ioc 容器
1 2 3 4 5 6 7 8 9 10 11 public  class  BeanTest      public  static  void  main (String[] args)           AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(BeanConfig.class);                  Person person = ioc.getBean(Person.class);         System.out.println(person);                   Person person01 = ioc.getBean("person01" , Person.class);         System.out.println(person01);      } } 
@ComponentScan 自动扫描 基本使用方法 通过 xml 方式配置自动扫描时需要用到 component-scan 
1 2 <context:component-scan  base-package ="com.szx" > </context:component-scan > 
同样也可以使用注解的方式来配置自动扫描指定包下面的所有类
value 指定扫描那些包下面的类 
includeFilters 设置只扫描声明了那个注解的类,但是要同时声明 useDefaultFilters = false
@ComponentScan.Filter 设置过滤方式
type = FilterType.ANNOTATION 根据注解扫描 
classes = Controller.class 扫描Controller注解 
 
 
 
 
useDefaultFilters 默认的扫描 
excludeFilters 设置不扫描声明了那个注解的类,它的参数和 includeFilters  相同 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Configuration @ComponentScan(         // 设置自动扫描那些包下面的类         value = "com.szx",         // 设置只扫描声明了Controller注解的类         includeFilters = {                 @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)         },         // 取消默认的扫描方式         useDefaultFilters = false ) public  class  MainConfig  } 
编写测试方法,查询当前ioc容器中的bean
1 2 3 4 5 6 7 8 9 @Test public  void  test ()     AnnotationConfigApplicationContext mainioc = new  AnnotationConfigApplicationContext(MainConfig.class);          String[] beanNames = mainioc.getBeanDefinitionNames();     for  (String beanName : beanNames) {         System.out.println(beanName);     } } 
因为设置了 includeFilters 只扫描 Controller 注解,所以结果如下
自定义@ComponentScan.Filter过滤规则 type 属性的几个值分别对应的含义
ANNOTATION 根据注解过滤 
ASSIGNABLE_TYPE 根据指定的类型过滤 
ASPECTJ 根据ASPECTJ表达式 
REGEX 根据正则表达式过滤 
CUSTOM 自定义过滤 
 
根据指定的类型过滤 ASSIGNABLE_TYPE ,示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 @ComponentScan(         // 设置自动扫描那些包下面的类         value = "com.szx",         // 设置只扫描声明了Controller注解的类         includeFilters = {                 // 设置ASSIGNABLE_TYPE指定Book类型扫描                 @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = Book.class)         },         // 取消默认的扫描方式         useDefaultFilters = false ) public  class  MainConfig  } 
扫描结果
自定义扫描规则 CUSTOM 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Configuration @ComponentScan(         // 设置自动扫描那些包下面的类         value = "com.szx",         // 设置只扫描声明了Controller注解的类         includeFilters = {                 // 自定义扫描规则 CUSTOM                 @ComponentScan.Filter(type = FilterType.CUSTOM ,classes = MyTypeFilter.class)         },         // 取消默认的扫描方式         useDefaultFilters = false ) public  class  MainConfig  } 
需要新建一个 MyTypeFilter 类并实现 TypeFilter 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package  com.szx.config;import  org.springframework.core.io.Resource;import  org.springframework.core.type.AnnotationMetadata;import  org.springframework.core.type.ClassMetadata;import  org.springframework.core.type.classreading.MetadataReader;import  org.springframework.core.type.classreading.MetadataReaderFactory;import  org.springframework.core.type.filter.TypeFilter;import  java.io.IOException;public  class  MyTypeFilter  implements  TypeFilter      @Override      public  boolean  match (MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)  throws  IOException                            AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();                  Resource resource = metadataReader.getResource();                  ClassMetadata classMetadata = metadataReader.getClassMetadata();                  String className = classMetadata.getClassName();                  if (className.contains("er" )){             return  true ;         }         return  false ;     } } 
运行测试方法,查看当前ioc容器中的bena
@Scope 调整作用域 @Scope 作用域有两个值
 singleton 单例的(默认值) 初始化ioc容器时会调用bean的初始化方法 
 prototype 多例的,初始化ioc容器时不会调用bean中的初始化方法 
 
首先新建一个配置类
1 2 3 4 5 6 7 8 9 10 11 12 @Configuration public  class  MainConfig2                     @Scope      @Bean      public  Person person ()          System.out.println("初始化person类bean" );         return  new  Person("李四" ,18 );     } } 
然后添加测试方法,从ioc容器中重复的取两边person,此时判断两个引用地址为用一个,判断返回 true
1 2 3 4 5 6 7 @Test public  void  test2 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig2.class);     Person person = ioc.getBean("person" , Person.class);     Person person2 = ioc.getBean("person" , Person.class);     System.out.println(person == person2);  } 
然后将配置类中的 @Scope 设置 prototype
1 2 3 4 5 @Scope("prototype") @Bean public  Person person ()     return  new  Person("李四" ,18 ); } 
然后再次执行测试方法会返回 false
其次当我们在初始化容器时两个状态也会有不同的情况,例如将测试方法中的 getBean 注释掉,只初始化一下 ioc 容器
1 2 3 4 5 6 7 @Test public  void  test2 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig2.class);      } 
然后修改配置类,在 new Person 之前打印一句话
1 2 3 4 5 6 7 8 9 10 11 12 @Configuration public  class  MainConfig2                     @Scope("prototype")      @Bean      public  Person person ()          System.out.println("实例化 Person" );         return  new  Person("李四" ,18 );     } } 
此时的作用域为 prototype,执行测试方法观察打印。发现控制台并没有任何打印,这说明在初始化ioc容器时并没有初始化bean
然后将测试方法中的 getBean 方法放开
然后将作用域改为 singleton,再来观察控制台输出
调用测试方法
会发现当作用域为singleton时在初始化ioc容器时就会实例化一下Person,当调用 getBean 时不会重复实例化
@Lazy 对象懒加载 设置对象懒加载,在初始化容器阶段不实例化对象,只在第一次获取时实例化,只针对单例有效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package  com.szx.config;import  com.szx.bean.Person;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Configuration;import  org.springframework.context.annotation.Lazy;import  org.springframework.context.annotation.Scope;@Configuration public  class  MainConfig2                     @Lazy       @Bean      public  Person person ()          System.out.println("实例化 Person" );         return  new  Person("李四" ,18 );     } } 
调用测试方法,重复获取两次,判断结果为 true
1 2 3 4 5 6 7 @Test public  void  test2 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig2.class);     Person person = ioc.getBean("person" , Person.class);     Person person2 = ioc.getBean("person" , Person.class);     System.out.println(person == person2);  } 
@Conditional 自定义条件注册bean @Conditional 注解可以自定义根据条件注册当前bean
添加配置类,根据操作环境注册不同的bean,@Conditional 接收一个Condition接口实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package  com.szx.config;import  com.szx.bean.Person;import  com.szx.conditional.LinuxConditional;import  com.szx.conditional.WindowConditional;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Conditional;import  org.springframework.context.annotation.Configuration;@Configuration public  class  MainConfig3      @Bean      public  Person lisi ()          return  new  Person("lisi" ,18 );     }          @Conditional(WindowConditional.class)      @Bean      public  Person bill ()          return  new  Person("bill" ,60 );     }          @Conditional(LinuxConditional.class)      @Bean      public  Person linus ()          return  new  Person("linus" ,43 );     } } 
添加 WindowConditional
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 package  com.szx.conditional;import  org.springframework.beans.factory.config.ConfigurableListableBeanFactory;import  org.springframework.beans.factory.support.BeanDefinitionRegistry;import  org.springframework.context.annotation.Condition;import  org.springframework.context.annotation.ConditionContext;import  org.springframework.core.env.Environment;import  org.springframework.core.type.AnnotatedTypeMetadata;public  class  WindowConditional  implements  Condition      @Override      public  boolean  matches (ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata)                    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();                  ClassLoader classLoader = context.getClassLoader();                  Environment environment = context.getEnvironment();                  BeanDefinitionRegistry registry = context.getRegistry();                  String osName = environment.getProperty("os.name" );         System.out.println(osName);                   if (osName.contains("Window" )){             return  true ;         }         return  false ;     } } 
添加 LinuxConditional
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package  com.szx.conditional;import  org.springframework.beans.factory.config.ConfigurableListableBeanFactory;import  org.springframework.beans.factory.support.BeanDefinitionRegistry;import  org.springframework.context.annotation.Condition;import  org.springframework.context.annotation.ConditionContext;import  org.springframework.core.env.Environment;import  org.springframework.core.type.AnnotatedTypeMetadata;public  class  LinuxConditional  implements  Condition      @Override      public  boolean  matches (ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata)                    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();                  ClassLoader classLoader = context.getClassLoader();                  Environment environment = context.getEnvironment();                  BeanDefinitionRegistry registry = context.getRegistry();                  String osName = environment.getProperty("os.name" );         System.out.println(osName);                   if (osName.contains("linux" )){             return  true ;         }         return  false ;     } } 
编写测试方法查看当前ioc容器中的bean
1 2 3 4 5 6 7 8 @Test public  void  test3 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig3.class);     String[] names = ioc.getBeanNamesForType(Person.class);     for  (String name : names) {         System.out.println(name);     } } 
运行测试方法,返回如下,因为操作系统是 Windows,所以 linus 不会被注册
@Import 快速注册bean 基本用法 除了使用 @Bean 的方式注册 bean 之外,也可以在类上使用 @Import 快速注册 bean
使用方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package  com.szx.config;import  com.szx.bean.Color;import  com.szx.bean.Order;import  com.szx.bean.Person;import  com.szx.conditional.LinuxConditional;import  com.szx.conditional.WindowConditional;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Conditional;import  org.springframework.context.annotation.Configuration;import  org.springframework.context.annotation.Import;@Import({Color.class, Order.class}) @Configuration public  class  MainConfig3      @Bean      public  Person lisi ()          return  new  Person("lisi" ,18 );     }          @Conditional(WindowConditional.class)      @Bean      public  Person bill ()          return  new  Person("bill" ,60 );     }          @Conditional(LinuxConditional.class)      @Bean      public  Person linus ()          return  new  Person("linus" ,43 );     } } 
调用测试方法获取当前ioc容器中的所有bean
1 2 3 4 5 6 7 8 @Test public  void  test3 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig3.class);     String[] names = ioc.getBeanDefinitionNames();     for  (String name : names) {         System.out.println(name);     } } 
使用 ImportSelector 导入类 ImportSelector 是一个接口,返回需要导入类的全类名组成的字符串数组。可以在 @Import 注解上传入 ImportSelector 实现类来完成导入
添加 ImportSelector 实现类 MyImportSelector 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package  com.szx.config;import  org.springframework.context.annotation.ImportSelector;import  org.springframework.core.type.AnnotationMetadata;public  class  MyImportSelect  implements  ImportSelector      @Override      public  String[] selectImports(AnnotationMetadata annotationMetadata) {                  return  new  String[]{"com.szx.bean.Yellor" ,"com.szx.bean.Blue" };     } } 
然后在配置类上添加 @Import 注解
执行测试方法,查看当前ioc容器中的bean
1 2 3 4 5 6 7 8 9 10 @Test public  void  test3 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig3.class);     String[] names = ioc.getBeanDefinitionNames();     for  (String name : names) {         System.out.println(name);     }     Blue blue = ioc.getBean("com.szx.bean.Blue" , Blue.class);     System.out.println(blue); } 
ImportBeanDefinitionRegistrar 手动注册bean ImportBeanDefinitionRegistrar 是一个接口,重写其 registerBeanDefinitions 方法,方法有两个参数
AnnotationMetadata 当前类的注解信息 
BeanDefinitionRegistry BeanDefinition的注册类 
 
首先编写 ImportBeanDefinitionRegistrar 实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package  com.szx.config;import  com.szx.bean.Rainbow;import  org.springframework.beans.factory.support.BeanDefinitionRegistry;import  org.springframework.beans.factory.support.RootBeanDefinition;import  org.springframework.context.annotation.ImportBeanDefinitionRegistrar;import  org.springframework.core.type.AnnotationMetadata;public  class  MyImportBeanDefinitionRegistrar  implements  ImportBeanDefinitionRegistrar      @Override      public  void  registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)                   boolean  b = registry.containsBeanDefinition("com.szx.bean.Blue" );         boolean  b1 = registry.containsBeanDefinition("com.szx.bean.Yellor" );         if (b && b1){                          RootBeanDefinition beanDefinition = new  RootBeanDefinition(Rainbow.class);             registry.registerBeanDefinition("rainbow" ,beanDefinition);         }     } } 
然后再配置类中的 @Import 注解上添加 MyImportBeanDefinitionRegistrar.class
执行测试方法查看当前ioc容器中的bean
1 2 3 4 5 6 7 8 9 10 @Test public  void  test3 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig3.class);     String[] names = ioc.getBeanDefinitionNames();     for  (String name : names) {         System.out.println(name);     }     Blue blue = ioc.getBean("com.szx.bean.Blue" , Blue.class);     System.out.println(blue); } 
通过 FactoryBean 工厂bean创建对象 FactoryBean 是一个接口,首先创建这个接口的实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package  com.szx.bean;import  org.springframework.beans.factory.FactoryBean;public  class  ColorFactoryBean  implements  FactoryBean <Color >     @Override      public  Color getObject ()  throws  Exception          System.out.println("创建Color实例" );         return  new  Color();     }     @Override      public  Class<?> getObjectType() {         return  Color.class;     }     @Override      public  boolean  isSingleton ()           return  true ;     } } 
在配置类中注册
1 2 3 4 5 6 @Bean public  ColorFactoryBean colorFactoryBean ()     return  new  ColorFactoryBean(); } 
首先调用测试方法查看当前ioc容器中的所有bean,可以看到存在 colorFactoryBean 对象
获取 colorFactoryBean 并打印这个对象的类型,获取工厂bean本身时需要在bean id前面添加 &
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public  void  test4 ()  throws  Exception     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig3.class);          Object colorFactoryBean = ioc.getBean("colorFactoryBean" );     Class<?> aClass = colorFactoryBean.getClass();           System.out.println("aClass = "  + aClass);           Object bean = ioc.getBean("&colorFactoryBean" );     System.out.println(bean.getClass());  } 
执行运行结果
@Bean 指定初始化和销毁方法 首先新建两个普通类,并分别定义 init 和 destroy 方法
新建 Car
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package  com.szx.bean;public  class  Car      public  Car ()           System.out.println("car constructor..." );     }          public  void  init ()          System.out.println("car init..." );     }          private  void  destroy ()           System.out.println("car destroy..." );     } } 
新建 Emp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package  com.szx.bean;public  class  Emp      public  Emp ()           System.out.println("emp constructor ..." );     }     public  void  init ()          System.out.println("emp init..." );     }     public  void  destroy ()          System.out.println("emp destroy ..." );     } } 
新建一个配置类,在这个配置类中注册 car 和 emp 两个 bean,其中emp为多例 bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package  com.szx.config;import  com.szx.bean.Car;import  com.szx.bean.Emp;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Configuration;import  org.springframework.context.annotation.Scope;@Configuration public  class  MainConfig4      @Bean(initMethod = "init",destroyMethod = "destroy")      public  Car car ()          return  new  Car();     }     @Scope("prototype")      @Bean(initMethod = "init",destroyMethod = "destroy")      public  Emp emp ()          return  new  Emp();     } } 
编写测试方法,查看两个对象的初始化方法和销毁方法调用时机
1 2 3 4 5 6 7 8 @Test public  void  test1 ()          AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig4.class);          ioc.close(); } 
首先只初始化容器和关闭容器,查看运行结果,可以看到多例bean emp的构造方法和init以及destroy方法都没有执行
然后现在加上获取 emp bean的方法
1 2 3 4 5 6 7 8 9 10 11 12 @Test public  void  test1 ()          AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig4.class);          ioc.getBean("emp" );               ioc.close(); } 
此时只调用了 emp 对象的构造方法和 init 方法,destroy 方法并没有被调用
总结:
单例bean
ioc容器创建时就调用对象的构造方法和init方法 
ioc容器关闭时会调用对象的destroy方法 
 
 
多例bean
ioc容器创建时不会调用对象的构造方法和init方法 
获取这个bean对象时才调用构造方法和init方法 
ioc容器关闭不会调用多例bean对象的destroy方法 
 
 
 
nitializingBean, DisposableBean 接口的使用 让一个类实现这两个接口即可实现初始化方法和销毁方法
创建接口实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package  com.szx.bean;import  org.springframework.beans.factory.DisposableBean;import  org.springframework.beans.factory.InitializingBean;import  org.springframework.context.annotation.Lazy;import  org.springframework.context.annotation.Scope;import  org.springframework.stereotype.Component;@Component public  class  Dep  implements  InitializingBean , DisposableBean      public  Dep ()           System.out.println("dep constructor ..." );     }          @Override      public  void  afterPropertiesSet ()  throws  Exception          System.out.println("dep init ..." );     }          @Override      public  void  destroy ()  throws  Exception          System.out.println("dep destroy ..." );     } } 
在配置类中添加 @ComponentScan("com.szx.bean") 注解自动扫描
执行测试方法查看初始化方法的打印
1 2 3 4 5 6 7 @Test public  void  test1 ()          AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig4.class);     ioc.close(); } 
运行效果
通过@PostConstruct和@PreDestroy指定初始化和销毁方法 
@PostConstruct 注解指定一个方法为属性赋值后调用的初始化方法 
@PreDestroy 注解指定一个方法为对象销毁调用的销毁方法 
 
新建一个 Dog 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package  com.szx.bean;import  org.springframework.stereotype.Component;import  javax.annotation.PostConstruct;import  javax.annotation.PreDestroy;@Component public  class  Dog      public  Dog ()           System.out.println("dog constructor..." );     }     @PostConstruct      public  void  init ()          System.out.println("dog init ..." );     }     @PreDestroy      public  void  destroy ()          System.out.println("dog destroy..." );     } } 
运行测试方法查询执行效果
1 2 3 4 5 6 7 @Test public  void  test1 ()          AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig4.class);     ioc.close(); } 
BeanPostProcessor后置处理器 BeanPostProcessor 是一个接口,要重写这个接口的两个方法,分别表示对象初始化之前调用,对象初始化之后调用
postProcessBeforeInitialization 对象初始化之前调用 
postProcessAfterInitialization 对象初始化之后调用 
 
创建实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package  com.szx.bean;import  org.springframework.beans.BeansException;import  org.springframework.beans.factory.config.BeanPostProcessor;import  org.springframework.lang.Nullable;import  org.springframework.stereotype.Component;@Component public  class  MyBeanPostProcess   implements  BeanPostProcessor      @Override      public  Object postProcessBeforeInitialization (Object bean, String beanName)  throws  BeansException          System.out.println(beanName + "初始化之前.." );         return  bean;     }     @Override      public  Object postProcessAfterInitialization (Object bean, String beanName)  throws  BeansException          System.out.println(beanName + "初始化之后.." );         return  bean;     } } 
执行测试方法,查看运行效果
1 2 3 4 5 6 7 @Test public  void  test1 ()          AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig4.class);     ioc.close(); } 
@Value注解给属性赋值 @Value 添加对象的属性上
可以是基本数据类型 
可以是SpEL表达式,例如 #{15-6} 
可以是 ${} ,读取外部配置文件 
 
新建一个配置类,里面注册一个 Person Bean
1 2 3 4 5 6 7 @Configuration public  class  MainConfig5      @Bean      public  Person person ()          return  new  Person();     } } 
然后打印这个ioc容器中的bean
1 2 3 4 5 6 7 8 @Test public  void  test1 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig5.class);     String[] beanNames = ioc.getBeanDefinitionNames();     for  (String beanName : beanNames) {         System.out.println(beanName);     } } 
现在来获取 person bean 查看属性值,可以看到现在都是 null
接着通过 @Value 注解对属性进行赋值
1 2 3 4 5 6 7 8 9 public  class  Person           @Value("张三")      String name;          @Value("#{15-6}")      Integer age;      } 
再来执行获取 person 方法,查看打印的对象值
@PropertySource 读取配置文件为属性赋值 首先新建一个配置文件 person.properties
然后在配置文件中使用 @PropertySource 配置数据源
value 是一个字符串数组,可以设置多个数据源 
encoding 设置读取配置文件的编码方式,使用 utf-8 解决读取中文乱码问题 
 
1 2 3 4 5 6 7 8 @PropertySource(value = {"classpath:person.properties"},encoding = "utf-8") @Configuration public  class  MainConfig5      @Bean      public  Person person ()          return  new  Person();     } } 
然后再 Person 类中使用 ${person.nickName} 的方式为 nickName 属性赋值
1 2 @Value("${person.nickName}") String nickName; 
执行测试方法,查看打印结果
1 2 3 4 5 6 @Test public  void  test1 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig5.class);     Person person = ioc.getBean("person" , Person.class);     System.out.println(person); }  
自动装配 @AutoWrite 新建一个 Bookdao
1 2 3 4 5 6 7 8 9 10 11 12 @Component public  class  BookDao      String bookName = "book1" ;     public  String getBookName ()           return  bookName;     }     public  void  setBookName (String bookName)           this .bookName = bookName;     } } 
然后新建 BookServer,使用 @Autowired 自动装配 bookDao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Service public  class  BookServer             }     public  BookDao getBookDao ()           return  bookDao;     }     public  void  setBookDao (BookDao bookDao)           this .bookDao = bookDao;     } } 
新建配置类 MainConfig6
1 2 3 4 5 @ComponentScan(value = {"com.szx.dao","com.szx.server"}) @Configuration public  class  MainConfig6       } 
添加测试方法,通过 BookServer 获取 bookDao 中的 bookName
1 2 3 4 5 6 7 8 9 public  class  AutowiredTest      @Test      public  void  test1 ()          AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig6.class);         BookServer bookServer = ioc.getBean("bookServer" , BookServer.class);         BookDao bookDao = bookServer.getBookDao();         System.out.println(bookDao.getBookName());     } } 
打印结果为book1
@Qualifier 使用 @AutoWrite 注解默认按照组件类型去容器中获取,如果容器中有两个相同类型的组件,再将属性的名称作为 id 去容器中查找
修改配置类,在配置类注册另外一个 BookDao 类型的组件,名称为 bookDao2
1 2 3 4 5 6 7 8 9 10 11 @ComponentScan(value = {"com.szx.dao","com.szx.server"}) @Configuration public  class  MainConfig6      @Bean      public  BookDao bookDao2 ()          BookDao bookDao = new  BookDao();         bookDao.setBookName("book2" );         return  bookDao;     } } 
运行测试方法,此时仍然打印 book1
如果才能打印 book2 呢?可以使用 @Qualifier 注解
在 BookServer 中添加 @Qualifier(“bookDao2”) 表示自动装配容器中名称为 bookDao2 的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package  com.szx.server;import  com.szx.dao.BookDao;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.beans.factory.annotation.Qualifier;import  org.springframework.stereotype.Service;@Service public  class  BookServer      @Qualifier("bookDao2")      @Autowired      BookDao bookDao;     public  BookServer ()       }     public  BookDao getBookDao ()           return  bookDao;     }     public  void  setBookDao (BookDao bookDao)           this .bookDao = bookDao;     } } 
执行测试方法
1 2 3 4 5 6 7 @Test public  void  test1 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig6.class);     BookServer bookServer = ioc.getBean("bookServer" , BookServer.class);     BookDao bookDao = bookServer.getBookDao();     System.out.println(bookDao.getBookName()); } 
@Primary 在bean对象上添加 @Primary 注解表示Spring自动装配时默认使用的首选 bean,此时就和 bean 名称无关
将 BookServer 中的 @Qualifier(“bookDao2”) 去掉,只留一个 @AutoWrite,此时正常情况下会装配 bookDao 对象
1 2 @Autowired BookDao bookDao; 
但是我们在配置类中注册的 bookDao2 上添加 @Primary 注解。此时就会装配 bookDao2
1 2 3 4 5 6 7 @Primary @Bean public  BookDao bookDao2 ()     BookDao bookDao = new  BookDao();     bookDao.setBookName("book2" );     return  bookDao; } 
运行测试方法,打印的是 book2
@AutoWrite自动装配的位置 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package  com.szx.bean;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.beans.factory.annotation.Qualifier;import  org.springframework.stereotype.Component;@Component public  class  Boos      Yellor yellor;     public  Boos ()       }     @Autowired      public  Boos (Yellor yellor)           this .yellor = yellor;     }     @Override      public  String toString ()           return  "Boos{"  +                 "yellor="  + yellor +                 '}' ;     } } 
自动装配Aware注入Spring底层组件 我们可以在自定义组件中注入Spring底层的一些组件,例如在组件中注入 applicationContext 
实现 ApplicationContextAware 接口,然后重写 setApplicationContext 方法,这个方法会以回调的方式自动执行
1 2 3 4 5 6 7 8 9 10 @Component public  class  MyAware  implements  ApplicationContextAware      ApplicationContext applicationContext;     @Override      public  void  setApplicationContext (ApplicationContext applicationContext)  throws  BeansException          this .applicationContext = applicationContext;         System.out.println("applicationContext = "  + applicationContext);     } } 
运行测试代码注册ioc容器,查看打印结果
1 2 3 4 5 @Test public  void  test1 ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig6.class);     System.out.println(ioc); } 
@Profile @Profile 注解可以根据环境自动切换装配不同的bean,例如配置的数据库引用地址。在开发环境我们连接的是 dev 库,生产环境下我们连接 produce 库。
环境搭建 首先新建数据库,分别新建 annotation_dev 和 annotation_product 
添加依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 <dependency >     <groupId > c3p0</groupId >      <artifactId > c3p0</artifactId >      <version > 0.9.1.2</version >  </dependency > <dependency >     <groupId > mysql</groupId >      <artifactId > mysql-connector-java</artifactId >      <version > 8.0.28</version >  </dependency > 
然后新建 jdbc.properties 配置文件
1 2 3 4 5 jdbc.name =root jdbc.pwd =abc123 jdbc.driver =com.mysql.jdbc.Driver jdbc.devUrl =jdbc:mysql://127.0.0.1:3306/annotation_dev jdbc.proUrl =jdbc:mysql://127.0.0.1:3306/annotation_product 
然后新建配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package  com.szx.config;import  com.mchange.v2.c3p0.ComboPooledDataSource;import  org.springframework.beans.factory.annotation.Value;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Configuration;import  org.springframework.context.annotation.PropertySource;import  javax.sql.DataSource;import  java.beans.PropertyVetoException;@PropertySource("classpath:jdbc.properties") @Configuration public  class  MainConfig7      @Value("${jdbc.name}")      String name;     @Value("${jdbc.pwd}")      String pwd;     @Value("${jdbc.devUrl}")      String devUrl;     @Value("${jdbc.proUrl}")      String proUrl;     @Value("${jdbc.driver}")      String driver;          @Bean      public  DataSource dataSourceDev ()  throws  PropertyVetoException          ComboPooledDataSource dataSource = new  ComboPooledDataSource();         dataSource.setUser(name);         dataSource.setPassword(pwd);         dataSource.setJdbcUrl(devUrl);         dataSource.setDriverClass(driver);         return  dataSource;     }          @Bean      public  DataSource dataSourceProduct ()  throws  PropertyVetoException          ComboPooledDataSource dataSource = new  ComboPooledDataSource();         dataSource.setUser(name);         dataSource.setPassword(pwd);         dataSource.setJdbcUrl(devUrl);         dataSource.setDriverClass(proUrl);         return  dataSource;     } } 
根据环境配置bean 首先在bean对象上添加 @Profile 注解,@Profile 注解可以自定义一个环境名称,和然后会自动根据当前环境自动装配相对应的bena。如果bean没有指定环境,则默认所有环境都进行装配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Bean public  Yellor yellor ()     return  new  Yellor(); } @Profile("dev") @Bean public  DataSource dataSourceDev ()  throws  PropertyVetoException     ComboPooledDataSource dataSource = new  ComboPooledDataSource();     dataSource.setUser(name);     dataSource.setPassword(pwd);     dataSource.setJdbcUrl(devUrl);     dataSource.setDriverClass(driver);     return  dataSource; } @Profile("product") @Bean public  DataSource dataSourceProduct ()  throws  PropertyVetoException     ComboPooledDataSource dataSource = new  ComboPooledDataSource();     dataSource.setUser(name);     dataSource.setPassword(pwd);     dataSource.setJdbcUrl(devUrl);     dataSource.setDriverClass(proUrl);     return  dataSource; } 
有两种方法:
方式一:设置启动参数 设置启动参数
添加启动配置,固定语句:-Dspring.profiles.active=product,product 就是要设置的环境名称
执行测试方法
1 2 3 4 5 6 7 8 @Test public  void  test1 ()      AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig7.class);     String[] beanNames = ioc.getBeanDefinitionNames();     for  (String beanName : beanNames) {         System.out.println(beanName);     } } 
通过图中可以看到 yellow 没有设置 @Profile,所以会被打印,但是 DataSource 类型的 bean 只打印了 dataSoruceProduct
修改启动参数 -Dspring.profiles.active=dev
方式二:通过代码方式设置启动环境 操作步骤:
使用空参构造器创建一个ioc容器 
设置需要激活的环境,可以设置多个 
注册配置类 
刷新容器 
 
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public  void  test2 ()          AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext();          ioc.getEnvironment().setActiveProfiles("dev" );          ioc.register(MainConfig7.class);          ioc.refresh();     String[] beanNames = ioc.getBeanDefinitionNames();     for  (String beanName : beanNames) {         System.out.println(beanName);     } } 
运行效果
@Profile设置位置 @Profile 注解除了可以设置 bean 上,也可以直接设置在配置类上,设置在配置类上表示当前配置类中的所有 bean 都会根据环境自动注册
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 package  com.szx.config;import  com.mchange.v2.c3p0.ComboPooledDataSource;import  com.szx.bean.Yellor;import  org.springframework.beans.factory.annotation.Value;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Configuration;import  org.springframework.context.annotation.Profile;import  org.springframework.context.annotation.PropertySource;import  javax.sql.DataSource;import  java.beans.PropertyVetoException;@Profile("dev") @PropertySource("classpath:jdbc.properties") @Configuration public  class  MainConfig7      @Value("${jdbc.name}")      String name;     @Value("${jdbc.pwd}")      String pwd;     @Value("${jdbc.devUrl}")      String devUrl;     @Value("${jdbc.proUrl}")      String proUrl;     @Value("${jdbc.driver}")      String driver;     @Bean      public  Yellor yellor ()          return  new  Yellor();     }          @Bean      public  DataSource dataSourceDev ()  throws  PropertyVetoException          ComboPooledDataSource dataSource = new  ComboPooledDataSource();         dataSource.setUser(name);         dataSource.setPassword(pwd);         dataSource.setJdbcUrl(devUrl);         dataSource.setDriverClass(driver);         return  dataSource;     }          @Bean      public  DataSource dataSourceProduct ()  throws  PropertyVetoException          ComboPooledDataSource dataSource = new  ComboPooledDataSource();         dataSource.setUser(name);         dataSource.setPassword(pwd);         dataSource.setJdbcUrl(devUrl);         dataSource.setDriverClass(proUrl);         return  dataSource;     } } 
然后修改测试方法,将环境设置为 product,但是上面的配置类添加了 @Profile(“dev”) 注解,表示只有在 dev 环境下才会注册,所以运行结果中就不会有任何 bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public  void  test2 ()          AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext();          ioc.getEnvironment().setActiveProfiles("product" );          ioc.register(MainConfig7.class);          ioc.refresh();     String[] beanNames = ioc.getBeanDefinitionNames();     for  (String beanName : beanNames) {         System.out.println(beanName);     } } 
运行结果
AOP功能测试 aop 指的是在程序运行期间动态的将某段代码切入到指定方法指定位置运行的编程方式。
设置步骤 
导入AOP依赖 spring-aspects 
定义一个业务逻辑类(MathFuns),在业务逻辑类中方法运行时将日志进行打印 
定义一个日志切面类(LogAspects),切面类里面的方法需要动态感知 MathFuns 类中方法的运行进度,进行通知
通知方法:
前置通知 @Before,方法开始调用之前执行 
后置通知 @After,方法运行结束后执行,无论方法执行成功还是失败都会执行 
成功返回通知 @AfterReturning,方法成功运行后执行 
异常返回通知 @AfterThrowing,方法运行出错后执行 
环绕通知 
 
 
 
 
给切面类中的目标方法添加不同的注解 
将切面类和逻辑类都添加到ioc容器中 
告诉Spring那个类才是切面类,添加 @Aspects 注解来表示该类是一个切面类 
在配置类上添加 @EnableAspectJAutoProxy 注解开启基于注解的aop模式 
 
代码演示 第一步:导入AOP依赖 spring-aspects
1 2 3 4 5 6 <dependency >     <groupId > org.springframework</groupId >      <artifactId > spring-aspects</artifactId >      <version > 5.2.22.RELEASE</version >  </dependency > 
第二步:定义一个业务逻辑类(MathFuns),在业务逻辑类中方法运行时将日志进行打印
1 2 3 4 5 6 7 public  class  MathFuns      public  int  div (int  i,int  j)          System.out.println("MathFuns.div 自己运行中.." );         return  i / j;     } } 
第三步:定义一个日志切面类(LogAspects),切面类里面的方法需要动态感知 MathFuns 类中方法的运行进度,进行通知
第四步:给切面类中的目标方法添加不同的注解
第六步:告诉Spring那个类才是切面类,添加 @Aspects 注解来表示该类是一个切面类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 package  com.szx.aop;import  org.aspectj.lang.JoinPoint;import  org.aspectj.lang.annotation.*;import  java.lang.reflect.Array;import  java.util.Arrays;import  java.util.List;@Aspect public  class  LogAspects      @Pointcut(value = "execution(* com.szx.aop.MathFuns.*(..))")           public  void  pointcut ()      @Before(value = "pointcut()")      public  void  logStart (JoinPoint joinPoint)                   String className = joinPoint.getSignature().getDeclaringTypeName();                  String methodName = joinPoint.getSignature().getName();                  Object[] args = joinPoint.getArgs();         List<Object> argList = Arrays.asList(args);         System.out.println(className + "."  + methodName + "方法开始调用,参数为:"  + argList);     }     @AfterReturning(value = "pointcut()",returning = "res")      public  void  logSucReturn (JoinPoint joinPoint,Object res)                   String className = joinPoint.getSignature().getDeclaringTypeName();                  String methodName = joinPoint.getSignature().getName();         System.out.println(className + "."  + methodName + "方法正常返回,返回结果:"  + res);     }     @AfterThrowing(value = "pointcut()",throwing = "error")      public  void  logErrReturn (JoinPoint joinPoint,Exception error)                   String className = joinPoint.getSignature().getDeclaringTypeName();                  String methodName = joinPoint.getSignature().getName();         System.out.println(className + "."  + methodName + "方法发生错误,错误信息:"  + error);     }     @After(value = "pointcut()")      public  void  logEnd (JoinPoint joinPoint)                   String className = joinPoint.getSignature().getDeclaringTypeName();                  String methodName = joinPoint.getSignature().getName();         System.out.println(className + "."  + methodName + "方法结束" );     } } 
第五步:将切面类和逻辑类都添加到ioc容器中
第七步:在配置类上添加 @EnableAspectJAutoProxy 注解开启基于注解的aop模式
1 2 3 4 5 6 7 8 9 10 11 12 13 @EnableAspectJAutoProxy @Configuration public  class  MainConfig8_AOP      @Bean      public  MathFuns mathFuns ()          return  new  MathFuns();     }     @Bean      public  LogAspects logAspects ()          return  new  LogAspects();     } } 
测试 添加测试方法,从ioc容器中获取 mathFuns 类
1 2 3 4 5 6 @Test public  void  test ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig8_AOP.class);     MathFuns mathFuns = ioc.getBean(MathFuns.class);     mathFuns.div(1 , 1 ); } 
运行结果:
如果我们手动的让方法发生错误,将除数设置为0
1 2 3 4 5 6 @Test public  void  test ()     AnnotationConfigApplicationContext ioc = new  AnnotationConfigApplicationContext(MainConfig8_AOP.class);     MathFuns mathFuns = ioc.getBean(MathFuns.class);     mathFuns.div(1 , 0 ); } 
运行结果:
声明式事务 环境搭建 首先导入相关依赖
spring 核心包 
jdbc 
c3p0数据库连接池 
mysql驱动 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <dependency >     <groupId > org.springframework</groupId >      <artifactId > spring-context</artifactId >      <version > 5.2.22.RELEASE</version >  </dependency > <dependency >     <groupId > org.springframework</groupId >      <artifactId > spring-jdbc</artifactId >      <version > 5.2.22.RELEASE</version >  </dependency > <dependency >     <groupId > c3p0</groupId >      <artifactId > c3p0</artifactId >      <version > 0.9.1.2</version >  </dependency > <dependency >     <groupId > mysql</groupId >      <artifactId > mysql-connector-java</artifactId >      <version > 8.0.28</version >  </dependency > 
新建 TxConfig 配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package  com.szx.tx;import  com.mchange.v2.c3p0.ComboPooledDataSource;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.ComponentScan;import  org.springframework.context.annotation.Configuration;import  org.springframework.jdbc.core.JdbcTemplate;import  javax.sql.DataSource;import  java.beans.PropertyVetoException;@ComponentScan("com.szx.tx") @Configuration public  class  TxConfig      @Bean      public  DataSource dataSource ()  throws  PropertyVetoException          ComboPooledDataSource dataSource = new  ComboPooledDataSource();         dataSource.setUser("root" );         dataSource.setPassword("abc123" );         dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/txdata" );         dataSource.setDriverClass("com.mysql.jdbc.Driver" );         return  dataSource;     }     @Bean      public  JdbcTemplate jdbcTemplate ()  throws  PropertyVetoException          JdbcTemplate jdbcTemplate = new  JdbcTemplate(dataSource());         return  jdbcTemplate;     } } 
新建 TxDao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package  com.szx.tx;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.jdbc.core.JdbcTemplate;import  org.springframework.stereotype.Component;@Component public  class  TxDao      @Autowired      JdbcTemplate jdbcTemplate;     public  void  addUser ()          String sql = "INSERT INTO users VALUES (null,?,?);" ;         jdbcTemplate.update(sql,"lisi" ,21 );     } } 
新建 TxServlet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package  com.szx.tx;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.stereotype.Service;@Service public  class  TxServlet      @Autowired      TxDao txDao;     public  void  addUser ()          txDao.addUser();     } } 
此时基本环境搭建配置完成,但是还没有引入事务相关注解
添加事务注解 第一步,在配置类上添加 @EnableTransactionManagement 注解开启声明式注解
第二步:在配置类中注册 PlatformTransactionManager 类型的bean
1 2 3 4 @Bean public  PlatformTransactionManager transactionManager ()  throws  PropertyVetoException     return  new  DataSourceTransactionManager(dataSource()); } 
第三步:在要实现添加事务的方法上添加 @Transactional 注解
1 2 3 4 5 @Transactional public  void  addUser ()     txDao.addUser();     Integer i = 10  /0 ; }