配置类:
package com.cetc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import com.cetc.bean.Person;
//该配置类就等同于配置文件
//Configuration注解标注该类为spring的配置类,该注解的实现上标注了@Compoent,用来说明被该注解标注的类是spring容器的一个组件
@Configuration
public class MainConfig {
@Bean(value = "person01")//容器中存放该对象的id值默认为方法名称,如果加上别名,则为别名的值
public Person person() {
return new Person("张三",55);
}
}
测试类:
package com.cetc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.bean.Person;
import com.cetc.config.MainConfig;
/**
* 主测试类
* @author LZX-PC
*
*/
public class MainTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
//2.用使用注解从容器中获取对象,id默认为@Bean所注解的方法名
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MainConfig.class);
Person person = (Person)applicationContext.getBean("person01");
System.out.println(person);
//根据类型获取目前spring容器中包含的对象的组件名称
String[] strings = applicationContext.getBeanNamesForType(Person.class);
for (String name : strings) {
System.out.println(name);
}
}
}
输出结果:
Person [name=张三, age=55]
person01
配置类:
package com.cetc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import com.cetc.bean.Person;
/**
1.includeFilters= {@Filter(type = FilterType.ANNOTATION,value= {Controller.class})}
它的意思是只显示被@Controller标注的类,必须搭配useDefaultFilters = false才能生效.
2.excludeFilters= {@Filter(type = FilterType.ANNOTATION,value= {Controller.class})}
它的意思是只显示排除@Controller标注的类,不需要搭配useDefaultFilters = false.
3.FilterType.ANNOTATION:使用注解进行过滤
FilterType.ASSIGNABLE_TYPE:使用类名进行过滤
FilterType.CUSTOM:使用自定义的类进行过滤,MyFilter类为自定义类
*/
@Configuration
@ComponentScans(value = {
@ComponentScan(value = "com.cetc",
includeFilters= {
@Filter(type = FilterType.ANNOTATION,value= {
Controller.class}),
@Filter(type = FilterType.ASSIGNABLE_TYPE,value = {
BookService.class}),
@Filter(type = FilterType.CUSTOM,value = {
MyFilter.class})
},useDefaultFilters = false)
})
public class MainConfig {
@Bean("person01")//容器中存放该对象的id值默认为方法名称,如果加上别名,则为别名的值
public Person person() {
return new Person("张三",55);
}
}
MyFilter
package com.cetc.filter;
import java.io.IOException;
import org.springframework.core.io.Resource;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
/**
自定义过滤类
*/
public class MyFilter implements TypeFilter{
//metadataReader:当前类的信息
//metadataReaderFactory:可以获取到其他类的信息
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
//扫描规定包下面的所有的类
Resource resource = metadataReader.getResource();
//获取当前包下面的所有类的类名
String filename = resource.getFilename();
//获取类名中包含Dao的类进行输出
if(filename.contains("Dao")) {
return true;
}
return false;
}
}
测试类:
package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.config.MainConfig;
public class IOCTest {
@Test
public void test01() {
@SuppressWarnings("resource")
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = applicationContext.getBeanDefinitionNames();
for (String name : names) {
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
bookController
bookDao
bookService
person01
配置类:
package com.cetc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import com.cetc.bean.Person;
@Configuration
public class MainConfig2 {
/**
* 1.SCOPE_SINGLETON singleton:单实例的,即IOC容器启动时,该实例就已经生成了,只生成一次,每次调用都是第一 次生成的实例
* 2.SCOPE_PROTOTYPE prototype:多实例的,即IOC容器启动时,并未生成该实例,等待调用的时候才生成该实例,并且 每调用一次都生成一个新的实例
* 3.TODO SCOPE_REQUEST request
* 4.TODO SCOPE_SESSION session
*/
@Scope("singleton")
@Bean
public Person person() {
System.out.println("创建Person对象...");
return new Person("张三",50);
}
}
测试类:
package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.bean.Person;
import com.cetc.config.MainConfig2;
public class IOCTest {
@Test
public void test01() {
@SuppressWarnings("resource")
//1.启动IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
System.out.println("IOC容器已经启动了...");
//2.调用IOC容器中的实例
Person person = (Person)applicationContext.getBean("person");
Person person1 = (Person)applicationContext.getBean("person");
System.out.println(person == person1);
}
}
输出结果:
当scope类型为singleton时结果为:
创建Person对象...
IOC容器已经启动了...
true
当scope类型为prototype时结果为:
IOC容器已经启动了...
创建Person对象...
创建Person对象...
false
配置类:
package com.cetc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import com.cetc.bean.Person;
@Configuration
public class MainConfig2 {
/**
* 单例模式下,IOC容器启动时不会创建Bean,第一次调用时再创建bean,只创建一次
*/
@Scope(scopeName = "singleton")
@Lazy
@Bean
public Person person() {
System.out.println("创建Person对象...");
return new Person("张三",50);
}
}
测试类:
package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.bean.Person;
import com.cetc.config.MainConfig2;
public class IOCTest {
@Test
public void test01() {
@SuppressWarnings("resource")
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MainConfig2.class);
System.out.println("IOC容器启动成功...");
// Person person = (Person)applicationContext.getBean("person");
// Person person1 = (Person)applicationContext.getBean("person");
// System.out.println(person == person1);
}
}
输出结果:
13、14、15行代码为未打开时的结果:
IOC容器启动成功...
13、14、15行代码打开后的结果:
IOC容器启动成功...
创建Person对象...
true
1.标注在方法上,意思是该方法满足条件后该@Bean标注的方法才生效
2.标注在类上,意思是该类满足条件后,该配置类总所有的@Bean才生效
源码解读:
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
*表示该注解允许多个类进行条件过滤,该类必须实现Condition,根据一定的条件筛选后,直至条件返回true
*然后将该条件类作为过滤的条件
*/
Class<? extends Condition>[] value();
}
//Condition接口
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
条件类1:
package com.cetc.condition;
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 WindowsCondition implements Condition{
/**
*
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取bean工厂
ConfigurableListableBeanFactory factory = context.getBeanFactory();
//获取类加载器
ClassLoader classLoader = context.getClassLoader();
//获取环境变量
Environment environment = context.getEnvironment();
//所有的类都是在此类中进行注册的
BeanDefinitionRegistry registry = context.getRegistry();
String name = environment.getProperty("os.name");
if(name.contains("Windows")) {
return true;
}
return false;
}
}
条件类2:
package com.cetc.condition;
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 LinuxCondition implements Condition{
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取bean工厂
ConfigurableListableBeanFactory factory = context.getBeanFactory();
//获取类加载器
ClassLoader classLoader = context.getClassLoader();
//获取环境变量
Environment environment = context.getEnvironment();
//所有的类都是在此类中进行注册的
BeanDefinitionRegistry registry = context.getRegistry();
String name = environment.getProperty("os.name");
if(name.contains("Linux")) {
return true;
}
return false;
}
}
配置类:
package com.cetc.config;
import java.awt.Window;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import com.cetc.bean.Person;
import com.cetc.condition.LinuxCondition;
import com.cetc.condition.WindowsCondition;
//@Conditional({WindowsCondition.class})
@Configuration
public class MainConfig2 {
@Conditional({
WindowsCondition.class})
@Bean
public Person person01() {
return new Person("window之父",67);
}
@Conditional({
LinuxCondition.class})
@Bean
public Person person02() {
return new Person("linux之父",48);
}
}
测试类:
package com.cetc.test;
import java.util.Map;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import com.cetc.bean.Person;
import com.cetc.config.MainConfig2;
public class IOCTest {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
@Test
public void test02(){
ConfigurableEnvironment environment = applicationContext.getEnvironment();
System.out.println("------->"+environment.getProperty("os.name"));
Map<String,Person> map = applicationContext.getBeansOfType(Person.class);
System.out.println(map);
}
}
输出结果:
//当操作系统为Windows时,输出结果为:
------->Windows 10
{
person01=Person [name=window之父, age=67]}
//当操作系统为Linux时,输出结果为:
------->Linux
{
person02=Person [name=linux之父, age=48]}
给容器导入组件的方式:
- 包扫描+组件标注注解(@Controller、@Service、@Repository、@Component)[自己写的类]或者给该类加上@Congfiguration注解,该注解的其实就是在@Component注解上又封装了一层,可以不配合包扫描单独使用
- @Bean[导入第三方包里的组件]
- @Import[快速给容器导入一个组件,相较于@Bean注解更简单便捷],有三种方式:
- 方式一:@Import(要导入容器中的组件),容器会自动注册这个组件,id默认为全类名
- 方式二:@ImportSelector
- 使用Spring提供的FactoryBean进行组件的注入
- 默认获取到的是工厂bean调用getObject()所创建的对象
- 要获取到工厂Bean本身,我们需要在id前面加上一个&符号:&beanFactoryBean
源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
* or regular component classes to import.
*/
Class<?>[] value();
}
方式一:
配置类:
package com.cetc.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.cetc.bean.Color;
@Configuration
@Import(value = {
Color.class})
public class MainConfig {
}
测试类:
package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.config.MainConfig;
public class ImportTest {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
@Test
public void test01() {
printBeanName();
}
public void printBeanName() {
String[] names = context.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
输出结果:
mainConfig
com.cetc.bean.Color
方式二:
配置类:
package com.cetc.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.cetc.bean.Color;
import com.cetc.condition.MyImportSelector;
@Configuration
@Import(value = {
Color.class,MyImportSelector.class})
public class MainConfig {
}
MyImportSelector类:
package com.cetc.condition;
import java.util.Set;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
* 自定义要导入的组件
*/
public class MyImportSelector implements ImportSelector {
/**
* 返回值String[]:返回所有注册的全类名
* AnnotationMetadata:定义了所有的注解
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//获取容器现存在所有注解的类型
Set<String> types = importingClassMetadata.getAnnotationTypes();
for (String type : types) {
System.out.println("--------->"+type);
//输出结果: --------->org.springframework.context.annotation.Configuration
// --------->org.springframework.context.annotation.Import
}
return new String[] {
"com.cetc.bean.Black","com.cetc.bean.Yellow","com.cetc.bean.Person"};
}
}
测试类:
package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.config.MainConfig;
public class ImportTest {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
@Test
public void test01() {
printBeanName();
}
public void printBeanName() {
String[] names = context.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
输出结果:
--------->org.springframework.context.annotation.Configuration
--------->org.springframework.context.annotation.Import
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
com.cetc.bean.Color
com.cetc.bean.Black
com.cetc.bean.Yellow
com.cetc.bean.Person
方式三:
配置类:
package com.cetc.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.cetc.bean.Color;
import com.cetc.condition.MyImportBeanDefinitionRegistrar;
import com.cetc.condition.MyImportSelector;
@Configuration
@Import(value = {
Color.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class MainConfig {
}
MyImportBeanDefinitionRegistrar类:
package com.cetc.condition;
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;
import com.cetc.bean.RainBow;
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* @param annotationMetadata:容器中注解的相关信息
* @param registry:注册类
*/
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
boolean flag1 = registry.containsBeanDefinition("com.cetc.bean.Black");
boolean flag2 = registry.containsBeanDefinition("com.cetc.bean.Yellow");
if(flag1 && flag2) {
//指定bean名
RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
registry.registerBeanDefinition("rainBow", beanDefinition);
}
}
}
测试类:
package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.config.MainConfig;
public class ImportTest {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
@Test
public void test01() {
printBeanName();
}
public void printBeanName() {
String[] names = context.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
输出结果:
mainConfig
com.cetc.bean.Color
com.cetc.bean.Black
com.cetc.bean.Yellow
com.cetc.bean.Person
rainBow
第四种方式:
配置类:
package com.cetc.bean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ColorFactoryBean implements FactoryBean<Color>{
private static int i = 1;
/**
* 通过getObject获取往工厂里面注入的bean
*/
public Color getObject() throws Exception {
System.out.println("调用第"+i+"次");
i++;
return new Color();
}
/**
* true :为单实例的,只创建一次Color对象
* false : 为多实例的,创建多个Color对象
*/
public boolean isSingleton() {
return true;
}
public Class<?> getObjectType() {
return null;
}
}
测试类:
package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.bean.ColorFactoryBean;
public class ImportTest {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ColorFactoryBean.class);
@Test
public void test01() {
printBeanName();
}
public void printBeanName() {
Object bean1 = context.getBean("colorFactoryBean");
Object bean2 = context.getBean("colorFactoryBean");
System.out.println("容器中该类的类型为:"+bean1.getClass());
System.out.println(bean1 == bean2);
}
}
输出结果:
调用第1次
容器中该类的类型为:class com.cetc.bean.Color
true
如果要获取工厂Bean本身:
测试类:
package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.bean.ColorFactoryBean;
public class ImportTest {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ColorFactoryBean.class);
@Test
public void test01() {
printBeanName();
}
public void printBeanName() {
Object bean1 = context.getBean("&colorFactoryBean");
Object bean2 = context.getBean("&colorFactoryBean");
System.out.println("容器中该类的类型为:"+bean1.getClass());
System.out.println(bean1 == bean2);
}
}
输出结果:
容器中该类的类型为:class com.cetc.bean.ColorFactoryBean$$EnhancerBySpringCGLIB$$f7f88f6e
true
关于容器管理Bean的生命周期:
我们可以自己定义bean的生命周期,当bean执行到当前生命周期时调用我们自定义的方法
创建Bean ------------------>初始化Bean------------------->销毁Bean
构造对象:
- 单实例:容器启动的时候创建对象
- 多实例:在每次调用的时候创建对象
初始化:
对象创建完成,并赋值好,调用初始化方法
销毁:
- 单实例情况下,当容器关闭后,调用我们自定义的销毁的方法
- 多实例情况下,需要我们手动关闭容器,它不会调用我们自定义的销毁方法
实现方式:
(1)采用@Bean指定init-method和destory-method
(2)通过让Bean实现InitializationBean(定义初始化逻辑)和DisposableBean(定义销毁逻辑)管理生命周期
(3)使用JSR250:
@PostConstruct:在bean创建完成并且赋值完成后,来执行初始化方法
@PreDestroy: 在容器销毁Bean之前通知我们进行清理操作
(4)使用BeanPostProcessor(后置处理器)
postProcessBeforeInitialization:在创建好对象并赋值结束之后立即调用
postProcessAfterInitialization:在初始化完成之后立即调用
4.BeanPostProcessor原理
//创建对象,交给IOC容器管理,然后给属性赋值
1.populateBean(beanName, mbd, instanceWrapper);
2.初始化
{
//前置处理器
2.1.applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
//调用InitializationBean或者的@Bean指定的方法或者JSR250注解标注的方法
2.2.invokeInitMethods(beanName, wrappedBean, mbd);
//后置处理器
2.3.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
因此,执行顺序是前置处理器—>JSR250—>InitializationBean—>后置处理器---->JSR250的destroy—>InitializationBean的destroy
4.Spring底层对BeanPostProcessor的应用:
bean赋值、注入其它组件等等都用到的前置处理器
单实例:
配置类:
package com.cetc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import com.cetc.bean.Car;
public class MainConfigOfLifeStyle {
@Bean(initMethod = "init" , destroyMethod = "destory")
@Scope(value = "singleton")
public Car car() {
return new Car();
}
}
Car:
package com.cetc.bean;
public class Car {
public Car() {
System.out.println("创建Car..........................");
}
public void init() {
System.out.println("初始化Car.........................");
}
public void destory() {
System.out.println("销毁Car............................");
}
}
测试类:
package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.bean.Car;
import com.cetc.config.MainConfigOfLifeStyle;
public class LifeStyleTest {
@Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeStyle.class);
Car car = (Car) context.getBean("car");
System.out.println(car);
context.close();
}
}
输出结果:
初始化Car.........................
com.cetc.bean.Car@a38d7a3
销毁Car............................
当@Scope的value值为prototype时,输出结果为:
创建Car..........................
初始化Car.........................
com.cetc.bean.Car@a38d7a3
注解版:
配置类:
package com.cetc.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Cat implements InitializingBean,DisposableBean{
public Cat() {
System.out.println("cat.........constructor.........");
}
public void destroy() throws Exception {
System.out.println("cat.....destroy.......");
}
public void afterPropertiesSet() throws Exception {
System.out.println("cat.......afterPropertiesSet........");
}
}
测试类:
@Test
public void test02() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Cat.class);
Cat cat = (Cat) context.getBean("cat");
System.out.println(cat);
context.close();
}
输出结果:
cat.........constructor.........
cat.......afterPropertiesSet........
com.cetc.bean.Cat$$EnhancerBySpringCGLIB$$4fb08bec@1dd02175
cat.....destroy.......
配置类:
@Configuration
public class Dog implements InitializingBean,DisposableBean{
public Dog() {
System.out.println("dog..........construct.........");
}
//创建对象并且赋值完成之后调用
@PostConstruct
public void init() {
System.out.println("Dog............PostConstruct........");
}
public void afterPropertiesSet() throws Exception {
System.out.println("dog........afterPropertiesSet............");
}
//容器移除对象之前
@PreDestroy
public void preDestroy() {
System.out.println("dog.........preDestory.......");
}
public void destroy() throws Exception {
System.out.println("dog.........destroy........");
}
}
测试类:
@Test
public void test03() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Dog.class);
Dog dog = (Dog) context.getBean("d1og");
context.close();
}
输出结果:
dog..........construct.........
Dog............PostConstruct........
dog........afterPropertiesSet............
dog.........preDestory.......
dog.........destroy........
配置类:
@Configuration
@ComponentScan("com.cetc.bean")
public class MainConfigOfLifeStyle {
@Bean
public Dog dog() {
return new Dog("柴犬...");
}
}
Dog类:
package com.cetc.bean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class Dog implements InitializingBean,DisposableBean{
private String name;
public Dog(String name) {
super();
System.out.println("dog..........construct........."+name);
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Dog() {
System.out.println("dog..........construct.........");
}
//创建对象并且赋值完成之后调用
@PostConstruct
public void init() {
System.out.println("Dog............PostConstruct........");
}
public void afterPropertiesSet() throws Exception {
System.out.println("dog........afterPropertiesSet............"+this.name);
}
//容器移除对象之前
@PreDestroy
public void preDestroy() {
System.out.println("dog.........preDestory......."+this.name);
}
public void destroy() throws Exception {
System.out.println("dog.........destroy........"+this.name);
}
}
MyBeanPostProcessor类:
package com.cetc.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* 后置处理器
* @author LZX-PC
*
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("....postProcessAfterInitialization...."+ beanName);
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("....postProcessBeforeInitialization...."+beanName);
return bean;
}
}
测试类:
@Test
public void test04() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeStyle.class);
context.close();
}
输出结果:
dog..........construct.........柴犬...
....postProcessBeforeInitialization....dog
Dog............PostConstruct........
dog........afterPropertiesSet............柴犬...
....postProcessAfterInitialization....dog
dog.........preDestory.......柴犬...
dog.........destroy........柴犬...
例如:ApplicationContextAware,首先ApplicationContextAware是一个接口,ApplicationContextAwareProcessor实现了BeanPostProcessor,下面请看源码分析:
ApplicationContextAware类:
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
ApplicationContextAwareProcessor部分源码:
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
//
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
//判断该bean是否是ApplicationContextAware的实现类,如果是,则执行ApplicationContextAware中定义 的方法,并且给applicationContext赋值
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
}
使用@Value赋值:
- 基本数值
- SPEL,#{}
- 可以写${},从属性中赋值,需要配合@PropertyValue使用
配置类:
@Configuration
@PropertySources(
{
@PropertySource(value = {
"classpath:/person.properties"}),
@PropertySource(value = {
"classpath:/person1.properties","classpath:/person2.properties"})
}
)
public class MainConfigPropertyValues {
@Bean
public Person person() {
return new Person();
}
}
properties文件:
person.nickName=xiao zhangsan
实体类:
public class Person {
@Value("zhangsan")
private String name;
@Value("#{20-2}")
private Integer age;
@Value("${person.nickName}")
...省略toString,get,set方法
}
测试类:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigPropertyValues.class);
@Test
public void test01() {
Person person = (Person) context.getBean("person");
System.out.println(person);
context.close();
}
输出结果:
Person [name=zhangsan, age=18, nickName=xiao zhangsan]
@Autowired&@Qualifier&@Primary配合进行自动注入:
默认按照类型进行装配,即找到容器中该类型的bean是谁,有几个这样类型的bean
如果找到有多个相同类型的组件,再根据属性的名称去作为ID去容器中查找,即
@Autowired private BookService bookService;中的bookService去容器中查找
@Qualifier(“bookDao”):使用@Qualifier指定要装配的组件的id,而不是属性名
自动装配无论是根据类型来找,还是属性名或者是@Qualifier指定的ID来找,前提是容器中得有组件注入,
如果没有,则会报错,我们可以通过@Autowired(required = false)来自动注入一个组件,找不到的话则为null
@Primary指定最高优先级,不能喝@Qualifier同时使用,它用于指定优先注入哪个组件
配置类:
@Configuration
@ComponentScan(value = {
"com.cetc.service","com.cetc.dao"})
public class MainConfigOfAutowired {
@Bean("bookDao02")
public BookDao bookDao() {
BookDao dao = new BookDao();
dao.setFlag("1");
return dao;
}
}
BookService:
@Service
public class BookService {
@Qualifier("bookDao")
@Autowired
private BookDao bookDao;
public void print() {
System.out.println(bookDao);
}
public BookDao getBookDao() {
return bookDao;
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
BookDao:
@Repository("bookDao")
public class BookDao {
private String flag = "0";
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
@Override
public String toString() {
return "BookDao [flag=" + flag + "]";
}
}
测试类:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
@Test
public void test01() {
BookService bookService = context.getBean(BookService.class);
bookService.print();
context.close();
}
输出结果:
BookDao [flag=0]
@Autowired除了放到属性位置外,还可以放置到参数、构造器、方法位置上
- 放到方法位置: 放到set方法位置,进行对象注入,默认是从容器中拿
- 放到构造器位置: 当有且只有一个有参构造器时,直接可以省略
- 参数位置: @Bean标注的方法上,参数位置的@Autowired注解也可以省略
标注在参数位置:
@Component
public class Boss {
private Money money;
public Money getMoney() {
return money;
}
//标注在参数位置,默认是从容器中拿money对象,当然,Money首先得是容器的一个组件
@Autowired
public void setMoney(Money money) {
this.money = money;
}
@Override
public String toString() {
return "Boss [money=" + money + "]";
}
}
标注在构造器上:
@Component
public class Boss {
private Money money;
public Money getMoney() {
return money;
}
/**容器初始化构建对象时,默认调用的是无参构造器,当有且只有一个有参构造器时,容器会调用有参构造,并且该注解可 以省略,也可以加到参数位置,也可以省略,默认是从容器中拿的对象,即下面三种方式等价:
@Autowired
public Boss(Money money) {
super();
System.out.println("执行了有参构造器....");
this.money = money;
}
public Boss(@Autowird Money money) {
super();
System.out.println("执行了有参构造器....");
this.money = money;
}
public Boss(Money money) {
super();
System.out.println("执行了有参构造器....");
this.money = money;
}
*/
@Autowired
public Boss(@Autowird Money money) {
super();
System.out.println("执行了有参构造器....");
this.money = money;
}
public void setMoney(Money money) {
this.money = money;
}
@Override
public String toString() {
return "Boss [money=" + money + "]";
}
}
标注在参数位置:
@Configuration
@ComponentScan(value = {
"com.cetc.bean"})
public class MainConfigOfAutowired {
//这种情况下,money对象从容器中获取,@Autowired也可以省略
@Bean
public Car car(@Autowired Money money) {
Car car = new Car();
car.setMoney(money);
return car;
}
}
@Resource&@Inject:
- @Resources(JSR250)注解,@Inject(JSR330)java规范的注解
- @Resources按照属性名称进行注入,不能配合@Primary以及没有required = false
- @Inject能配合@Primary使用,但是没有required = false以及注解后面不能指定一些属性,如name属性,不太实用
配置类同上
BookService:
//@Resource(name = "bookDao02")
@Inject//后面不能指定值
private BookDao bookDao;
public void print() {
System.out.println(bookDao);
}
public BookDao getBookDao() {
return bookDao;
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
详解见生命周期-BeanPostProcessor的应用
Aware接口的实现类:
配置类:
@Component
public class Color implements ApplicationContextAware,EmbeddedValueResolverAware,BeanNameAware{
public ApplicationContext applicationContext = null;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("获取IOC容器:"+applicationContext);
this.applicationContext = applicationContext;
}
public void setBeanName(String name) {
System.out.println("current bean name is :"+name);
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
String stringValue = resolver.resolveStringValue("你好啊,${os.name},我是#{12*30}");
System.out.println(stringValue);
}
}
配置类:
@Configuration
@ComponentScan(value = {
"com.cetc.bean"})
public class MainConfigOfAutowired {
}
测试类:
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
@Test
public void test01() {
}
输出结果:
你好啊,Windows 10,我是360
获取IOC容器:org.springframework.context.annotation.AnnotationConfigApplicationContext@59f95c5d: startup date [Sat Sep 19 11:26:24 CST 2015]; root of context hierarchy
- 注解源码:
@Target({ ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(ProfileCondition.class) public @interface Profile { String[] value(); }
- 基本规则:
- 标注在方法上:先由方法向容器中注入组件,然后约定环境的名字,接下来是启动时具体激活哪个约定好的名字。
- 标记在类上,表示只有启动时的环境为当前配置类约定的环境时,该配置类下的方法才起作用
- 最后,在配置类中配置的其他方法不受标注在方法上的@Profile影响,容器启动,然后正常注入组件
- 激活方法:
- 在启动时添加环境变量: -Dspring.profiles.active=环境定义的名称(如 test、dev、prod)
- 使用代码激活,见代码
jdbc.properties
db.username=root
db.password=root
db.driverClass=com.jdbc.mysql.Driver
db.testUrl=jdbc:mysql://localhost:3306/test
db.devUrl=jdbc:mysql://localhost:3306/dev
db.prodUrl=jdbc:mysql://localhost:3306/produ
配置类:
@Configuration
@PropertySource(value = "classpath:/jdbc.properties")
public class MainConfigProfile {
@Value("db.username")
private String userName;
@Value("db.password")
private String password;
@Value("db.driverClass")
private String driverClass;
@Value("db.testUrl")
private String testUrl;
@Value("db.devUrl")
private String devUrl;
@Value("db.prodUrl")
private String prodUrl;
//添加环境属性
@Profile("test")
@Bean("test")
public DataSource dataSource() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(userName);
dataSource.setPassword(password);
dataSource.setJdbcUrl(testUrl);
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("dev")
@Bean("dev")
public DataSource dataSource01() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(userName);
dataSource.setPassword(password);
dataSource.setJdbcUrl(devUrl);
dataSource.setDriverClass(driverClass);
return dataSource;
}
//@Profile("default"):当是default,不需要任何激活,容器启动候,默认使用该环境
@Profile("prod")
@Bean("prod")
public DataSource dataSource02() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(userName);
dataSource.setPassword(password);
dataSource.setJdbcUrl(prodUrl);
dataSource.setDriverClass(driverClass);
return dataSource;
}
//只要不在该类上添加@Profile,该对象的注入是不受其他方法影响的
@Bean
public Car car() {
return new Car();
}
}
测试类:
public class MainConfigProfileTest {
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigProfile.class);
@Test
public void test01() {
String[] arrs = context.getBeanNamesForType(DataSource.class);
for (String arr : arrs) {
System.out.println(arr);
}
Object bean = context.getBean(Car.class);
System.out.println(bean);
}
}
输出结果:
dev
Car [money=null]
使用代码激活环境变量:
@Test
public void test01() {
//启动IOC容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//设置环境变量
context.getEnvironment().setActiveProfiles("dev");
//注册组件
context.register(MainConfigProfile.class);
//刷新容器
context.refresh();
String[] arrs = context.getBeanNamesForType(DataSource.class);
for (String arr : arrs) {
System.out.println(arr);
}
Object bean = context.getBean(Car.class);
System.out.println(bean);
}
输出结果:
dev
Car [money=null]