博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring注解驱动开发(一)
阅读量:3915 次
发布时间:2019-05-23

本文共 11574 字,大约阅读时间需要 38 分钟。

目录


一、组件注册

@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定义的FactoryBeanpublic class ColorFactoryBean implements FactoryBean
{ //返回一个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

@Componentpublic 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(定义销毁逻辑)。

@Componentpublic 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之前通知我们进行清理工作

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

 

BeanPostProcessor(bean的后置处理器)

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

postProcessBeforeInitialization:在初始化之前工作

postProcessAfterInitialization:在初始化之后工作

/** * 后置处理器:初始化前后进行处理工作 * 将后置处理器加入到容器中 * @author lfy */@Componentpublic 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"})@Configurationpublic 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;	}	}
@Repositorypublic 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 + "]";	}}
@Servicepublic 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

@Servicepublic 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;	}}

 

 

未完待续~~~~

转载地址:http://ffirn.baihongyu.com/

你可能感兴趣的文章
一位资深程序员大牛给予Java初学者的学习路线建议
查看>>
浅谈Java中的hashcode方法
查看>>
Java NIO:NIO概述
查看>>
Java中的static关键字解析
查看>>
Java多态性理解
查看>>
Java IO流学习总结
查看>>
Java发送http的get、post请求
查看>>
Java中volatile关键字的含义
查看>>
给Java程序猿们推荐一些值得一看的好书
查看>>
Java这些冷知识你知道吗?
查看>>
假如时光倒流,我会这么学习Java
查看>>
一位10年Java工作经验的架构师聊Java和工作经验
查看>>
Java项目经验——程序员成长的钥匙
查看>>
假如时光倒流,我会这么学习Java
查看>>
一位资深程序员大牛给予Java初学者的学习路线建议
查看>>
Java后端2017书单推荐
查看>>
Java的内存回收机制
查看>>
2年Java开发工作经验面试总结
查看>>
最全面的Java多线程用法解析
查看>>
Java ClassLoader 原理详细分析
查看>>