天天看点

Spring注解驱动开发(一)一、组件注册二、生命周期三、属性赋值四、自动装配

目录

一、组件注册

@Configuration

@Bean

@ComponentScan

@Scope

@Lazy

@Conditional

@import

FactoryBean

二、生命周期

@Bean指定初始化和销毁方法

实现InitializingBean和DisposableBean接口

JSR250

BeanPostProcessor(bean的后置处理器)

总结

三、属性赋值

@PropertySource

@Value

四、自动装配

@Autowired

@Qualifier

@Primary

一、组件注册

@Configuration

作用:告诉Spring这是一个配置类
@Configuration  //告诉Spring这是一个配置类
public class MainConfig {}
           

@Bean

作用:给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id,也可以通过value属性设置id
@Configuration  //告诉Spring这是一个配置类
public class MainConfig {
	//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
	@Bean("person")
	public Person person01(){
		return new Person("lisi", 20);
	}
}
           

@ComponentScan

作用:开启组件扫描

参数:

value:指定要扫描的包

excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件

includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件

FilterType.ANNOTATION:按照注解类型过滤

FilterType.ASSIGNABLE_TYPE:按照给定的类型过滤

FilterType.ASPECTJ:使用ASPECTJ表达式过滤

FilterType.REGEX:使用正则表达式过滤

FilterType.CUSTOM:使用自定义规则过滤

@Configuration  //告诉Spring这是一个配置类
@ComponentScans(
		value = {
				@ComponentScan(value="com.atguigu",includeFilters = {
/*						@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
						@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),*/
						@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
				},useDefaultFilters = false)	
		}
		)
public class MainConfig {
	@Bean("person")
	public Person person01(){
		return new Person("lisi", 20);
	}

}
           

自定义规则

public class MyTypeFilter implements TypeFilter {

	/**
	 * metadataReader:读取到的当前正在扫描的类的信息
	 * metadataReaderFactory:可以获取到其他任何类信息的
	 */
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		// TODO Auto-generated method stub
		//获取当前类注解的信息
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		//获取当前正在扫描的类的类信息
		ClassMetadata classMetadata = metadataReader.getClassMetadata();
		//获取当前类资源(类的路径)
		Resource resource = metadataReader.getResource();
		
		String className = classMetadata.getClassName();
		System.out.println("--->"+className);
		if(className.contains("er")){
			return true;
		}
		return false;
	}

}
           

@Scope

作用:调整JavaBean的作用域

参数:

prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。(每次获取的时候才会调用方法创建对象)

singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。(以后每次获取就是直接从容器map.get()中拿)

request:同一次请求创建一个实例

session:同一个session创建一个实例

@Scope("prototype")
	@Bean("person")
	public Person person(){
		System.out.println("给容器中添加Person....");
		return new Person("张三", 25);
	}
           

@Lazy

作用:懒加载

说明:

单实例bean会默认在容器启动的时候创建对象,懒加载即在容器启动时不创建对象。第一次使用(获取)Bean创建对象,并初始化;

@Lazy
	@Bean("person")
	public Person person(){
		System.out.println("给容器中添加Person....");
		return new Person("张三", 25);
	}
           

@Conditional

作用:按照一定的条件进行判断,满足条件给容器中注册bean

示例:

(1)如果系统是windows,给容器中注册("bill")

(2)如果是linux系统,给容器中注册("linus")

判定条件(Linux)

//判断是否linux系统
public class LinuxCondition implements Condition {

	/**
	 * ConditionContext:判断条件能使用的上下文(环境)
	 * AnnotatedTypeMetadata:注释信息
	 */
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO是否linux系统
		//1、能获取到ioc使用的beanfactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//2、获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		//3、获取当前环境信息
		Environment environment = context.getEnvironment();
		//4、获取到bean定义的注册类
		BeanDefinitionRegistry registry = context.getRegistry();
		
		String property = environment.getProperty("os.name");
		
		//可以判断容器中的bean注册情况,也可以给容器中注册bean
		boolean definition = registry.containsBeanDefinition("person");
		if(property.contains("linux")){
			return true;
		}
		
		return false;
	}

}
           

 判断条件(Windows)

//判断是否windows系统
public class WindowsCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Environment environment = context.getEnvironment();
		String property = environment.getProperty("os.name");
		if(property.contains("Windows")){
			return true;
		}
		return false;
	}

}
           

注解使用示例 

@Conditional(WindowsCondition.class)
    @Bean("bill")
	public Person person01(){
		return new Person("Bill Gates",62);
	}
	
	@Conditional(LinuxCondition.class)
	@Bean("linus")
	public Person person02(){
		return new Person("linus", 48);
	}
           

@import

作用:快速给容器中导入一个组件

方式:

1)@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名

2)ImportSelector:返回需要导入的组件的全类名数组;

3)ImportBeanDefinitionRegistrar:手动注册bean到容器中

 实现ImportSelector接口

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {

	//返回值,就是到导入到容器中的组件全类名
	//AnnotationMetadata:当前标注@Import注解的类的所有注解信息
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		//方法不要返回null值
		return new String[]{"com.atguigu.bean.Blue","com.atguigu.bean.Yellow"};
	}

}
           

 实现ImportBeanDefinitionRegistrar接口

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * AnnotationMetadata:当前类的注解信息
	 * BeanDefinitionRegistry:BeanDefinition注册类;
	 * 		把所有需要添加到容器中的bean;调用
	 * 		BeanDefinitionRegistry.registerBeanDefinition手工注册进来
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		
		boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red");
		boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue");
		if(definition && definition2){
			//指定Bean定义信息;(Bean的类型,Bean。。。)
			RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
			//注册一个Bean,指定bean名
			registry.registerBeanDefinition("rainBow", beanDefinition);
		}
	}
}
           

注解使用示例 

//类中组件统一设置。满足当前条件,这个类中配置的所有bean注册才能生效;
@Conditional({WindowsCondition.class})
@Configuration
@Import({Color.class,Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {}
           

FactoryBean

作用:使用Spring提供的 FactoryBean(工厂Bean)

特点:

1)、默认获取到的是工厂bean调用getObject创建的对象

2)、要获取工厂Bean本身,我们需要给id前面加一个& (&colorFactoryBean)

Object bean4 = applicationContext.getBean("&colorFactoryBean");
           

实现FactoryBean接口

//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {

	//返回一个Color对象,这个对象会添加到容器中
	@Override
	public Color getObject() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("ColorFactoryBean...getObject...");
		return new Color();
	}

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

	//是单例?
	//true:这个bean是单实例,在容器中保存一份
	//false:多实例,每次获取都会创建一个新的bean;
	@Override
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return false;
	}

}
           

二、生命周期

@Bean指定初始化和销毁方法

说明:通过@Bean指定init-method和destroy-method

Car.class

@Component
public class Car {
	
	public Car(){
		System.out.println("car constructor...");
	}
	
	public void init(){
		System.out.println("car ... init...");
	}
	
	public void detory(){
		System.out.println("car ... detory...");
	}

}
           
@Bean(initMethod="init",destroyMethod="detory")
	public Car car(){
		return new Car();
	}
           

实现InitializingBean和DisposableBean接口

说明:通过让Bean实现InitializingBean(定义初始化逻辑);DisposableBean(定义销毁逻辑)。
@Component
public class Cat implements InitializingBean,DisposableBean {
	
	public Cat(){
		System.out.println("cat constructor...");
	}

	@Override
	public void destroy() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat...destroy...");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat...afterPropertiesSet...");
	}

}
           

JSR250

说明:

@PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法

@PreDestroy:在容器销毁bean之前通知我们进行清理工作

@Component
public class Dog implements ApplicationContextAware {
	
	public Dog(){
		System.out.println("dog constructor...");
	}
	
	//对象创建并赋值之后调用
	@PostConstruct
	public void init(){
		System.out.println("[email protected]...");
	}
	
	//容器移除对象之前
	@PreDestroy
	public void detory(){
		System.out.println("[email protected]...");
	}
}
           

BeanPostProcessor(bean的后置处理器)

说明:在bean初始化前后进行一些处理工作。

postProcessBeforeInitialization:在初始化之前工作

postProcessAfterInitialization:在初始化之后工作

/**
 * 后置处理器:初始化前后进行处理工作
 * 将后置处理器加入到容器中
 * @author lfy
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
		return bean;
	}

}
           

总结

1.关于初始化和销毁

(1)初始化:对象创建完成,并赋值好,调用初始化方法。。。

(2)销毁:单实例:容器关闭的时候;多实例:容器不会管理这个bean;容器不会调用销毁方法;

2.BeanPostProcessor原理

第一步

(1)populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值

第二步

(2)initializeBean(调用初始化方法)

(2.1)applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);在初始化之前执行

(2.2)invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化

(2.3)applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);在初始化之后执行

3.Spring底层对 BeanPostProcessor 的使用

(1)bean赋值,注入其他组件

(2)@Autowired,生命周期注解功能

(3)@Async,xxx BeanPostProcessor;

三、属性赋值

@PropertySource

说明:使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中;加载完外部的配置文件以后使用${}取出配置文件的值

 person.properties配置文件

person.nickName=小张三
           

配置类中引入配置文件 

@PropertySource(value={"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {
	
	@Bean
	public Person person(){
		return new Person();
	}

}
           

@Value

可以赋值的类型:

1、基本数值

2、可以写SpEL; #{}

3、可以写${};取出配置文件【properties】中的值(在运行环境变量里面的值)

public class Person {

	@Value("张三")
	private String name;
	@Value("#{20-2}")
	private Integer age;
	
	@Value("${person.nickName}")
	private String nickName;
	
	public String getNickName() {
		return nickName;
	}
	public void setNickName(String nickName) {
		this.nickName = nickName;
	}
	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) {
		super();
		this.name = name;
		this.age = age;
	}
	public Person() {
		super();
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";
	}

}
           

四、自动装配

@Autowired

特点:

(1)默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);找到就赋值

(2)如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找applicationContext.getBean("bookDao")

(3)可以使用@Autowired(required=false),允许找不到对应的JavaBean对象。

示例:如下有两个BookDao的实现类,自动装配默认会去绑定属性名称相同的实现类,即bookDao,而不是bookDao2

@Configuration
@ComponentScan({"com.atguigu.service","com.atguigu.dao",
	"com.atguigu.controller","com.atguigu.bean"})
public class MainConifgOfAutowired {
	
	@Bean("bookDao2")
	public BookDao bookDao(){
		BookDao bookDao = new BookDao();
		bookDao.setLable("2");
		return bookDao;
	}	
}
           
@Repository
public class BookDao {
	
	private String lable = "1";

	public String getLable() {
		return lable;
	}

	public void setLable(String lable) {
		this.lable = lable;
	}

	@Override
	public String toString() {
		return "BookDao [lable=" + lable + "]";
	}

}
           
@Service
public class BookService {
	
	@Autowired(required=false)
	private BookDao bookDao;
	
	public void print(){
		System.out.println(bookDao);
	}

	@Override
	public String toString() {
		return "BookService [bookDao=" + bookDao + "]";
	}
}
           

@Qualifier

作用:使用@Qualifier指定需要装配的组件的id,而不是使用属性名

示例:如下代码,自动装配的是bookDao而不是bookDao2

@Service
public class BookService {
	
	@Qualifier("bookDao")
	@Autowired()
	private BookDao bookDao2;
	
	public void print(){
		System.out.println(bookDao);
	}

	@Override
	public String toString() {
		return "BookService [bookDao=" + bookDao + "]";
	}	
}
           

@Primary

作用:让Spring进行自动装配的时候,默认使用首选的bean;也可以继续使用@Qualifier指定需要装配的bean的名字
@Configuration
@ComponentScan({"com.atguigu.service","com.atguigu.dao",
	"com.atguigu.controller","com.atguigu.bean"})
public class MainConifgOfAutowired {
	
	@Primary
	@Bean("bookDao2")
	public BookDao bookDao(){
		BookDao bookDao = new BookDao();
		bookDao.setLable("2");
		return bookDao;
	}
}
           

未完待续~~~~