Spring笔记(2) - 生命周期/属性赋值/自动装配及部分源码解析
一.生命周期
@Bean自定义初始化和销毁方法
//====xml方式: init-method和destroy-method====
<bean id="person" class="com.hrh.bean.Person" scope="singleton" init-method="" destroy-method="">
<property name="name" value="张三"></property>
<property name="age" value="20"></property>
</bean>
//====@Bean方式====
/**
*单实例:只调用initMethod一次,容器关闭时会调用destroyMethod
*多实例: 每次调用Bean都调用initMethod,容器关闭不会调用destroyMethod,需要手动调用
**/
@Bean(initMethod = "",destroyMethod = "")
public Person person() {
System.out.println("注入容器。。。。。");
return new Person("张三", 20);
}
//====实现接口方式====
/**
* InitializingBean:定义初始化逻辑,实现afterPropertiesSet()
* DisposableBean:定义销毁逻辑,实现destroy()
*/
@Component
public class Person implements InitializingBean, DisposableBean {
public Person(){
System.out.println("Person 。。。 constructor");
} @Override
public void afterPropertiesSet() throws Exception {
System.out.println("Person 。。。afterPropertiesSet");
} @Override
public void destroy() throws DestroyFailedException {
System.out.println("Person 。。。destroy");
}
}
@Configurable
@ComponentScan(value = "com.hrh")
public class BeanConfig {} AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
context.close();@PostConstruct和@PreDestroy
/**
* JSR250:
* @PostConstruct: 在bean创建完成并且属性赋值完成后,来执行初始化方法
* @PreDestroy :在容器销毁bean之前通知进行清理工作
*/
@Component
public class Color {
public Color() {
System.out.println("Color 。。。 constructor");
} @PostConstruct//对象创建并赋值之后调用
public void init() throws Exception {
System.out.println("Color 。。。init");
} @PreDestroy//容器移除对象之前
public void destroy() {
System.out.println("Color 。。。destroy");
}
}BeanPostProcessor:bean后置处理器,对bean初始化之前和之后的处理,上文的@PostConstruct和@PreDestroy就是使用了该类实现的
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
*
* @param bean 容器创建的实例
* @param beanName 容器创建实例的名字
* @return 创建的实例或进行包装后的实例
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization====>【"+bean+"】:"+beanName);
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization====>【"+bean+"】:"+beanName);
return bean;
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
}原理:从doCreateBean可以看到,在对bean进行属性赋值后,调用initializeBean初始化bean,在initializeBean中会在调用初始化方法前后会遍历所有的BeanPostProcessor实现的方法
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
....
refresh();//刷新容器
}
public void refresh() throws BeansException, IllegalStateException {
...
//初始化剩下所有的(非懒加载的)单实例对象
finishBeanFactoryInitialization(beanFactory);
}
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
...
//初始化剩下所有的(非懒加载的)单实例对象
beanFactory.preInstantiateSingletons();
}
public void preInstantiateSingletons() throws BeansException {
...
getBean(beanName);
...
}
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
...
//getSingleton获取实例
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);//创建实例
}
...
}
});
...
return (T) bean;
} protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
...
Object beanInstance = doCreateBean(beanName, mbdToUse, args);//创建实例
...
return beanInstance;
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
...
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);//对属性赋值
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);//初始化对象,相当后置处理器的调用
}
}
...
return exposedObject;
}
//从下面可以看到,在执行初始化方法之前,执行applyBeanPostProcessorsBeforeInitialization,执行完初始化方法之后,执行applyBeanPostProcessorsAfterInitialization
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
...
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
...
invokeInitMethods(beanName, wrappedBean, mbd);//执行初始化方法
...
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
//遍历执行实现了BeanPostProcessor接口的类,比如MyBeanPostProcessor,然后执行实现类的重写方法
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
InitDestroyAnnotationBeanPostProcessor:处理@PostConstruct和@PreDestroy
/**
* 处理javax.annotation.PostConstruct注解
*/
public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
this.initAnnotationType = initAnnotationType;
}
/**
* 处理javax.annotation.PreDestroy注解
*/
public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
this.destroyAnnotationType = destroyAnnotationType;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//找到了使用@PostConstruct和@PreDestroy的类的生命周期注解
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
//对每个注解上的方法进行反射执行
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
public void invokeInitMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
Collection<LifecycleElement> initMethodsToIterate =
(checkedInitMethods != null ? checkedInitMethods : this.initMethods);
if (!initMethodsToIterate.isEmpty()) {
for (LifecycleElement element : initMethodsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
}
//element包含注解和注解上的方法
element.invoke(target);//执行每个注解上的方法
}
}
}
二.属性赋值
@Value
public class Person {
/**
* @Value :基本数值,SpEL表达式 #{}, ${}获取配置文件的值
*/
@Value("张三")
private String name;
@Value("#{20-1}")
private Integer age;
}@PropertySource:读取外部配置文件中k/v的数据
public class Person{
/**
* @Value :基本数值,SpEL表达式 #{}, ${}获取配置文件的值
*/
@Value("张三")
private String name;
@Value("#{20-1}")
private Integer age;
@Value("${sex}")
private String sex;
}
@PropertySource(value = "classpath:/global.properties")
@Configurable
public class BeanConfig {} global.properties
sex=男
三.自动装配
@Autowired&@Qualifier&@Primary:Spring定义
@Service
public class UserService {
/**
* @Autowired :自动注入
* 1)默认优先按照类型去容器中对应的组件:context.getBean(UserDao.class);
* 2)如果有多少相同类型的组件,需要将属性的名称作为id去容器查找:(UserDao) context.getBean("userDao1")
* 3)@Qualifier("userDao1"):指定需要装配的组件id,而不是使用默认属性;优先级比@Primary高
* 4)如果UserDao没有注入容器(@Repository和 @Bean):启用@Autowired会报空指针异常,需要required = false,表示从容器中找到就自动装配,找不到就设为null
* 5)@Primary表示Spring自动装配时,默认使用首选的bean
*/
@Qualifier("userDao")
@Autowired
private UserDao userDao; public void printf() {
System.out.println(userDao);
}
}
@Repository
public class UserDao {
private String id ="1"; public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} @Override
public String toString() {
return "UserDao{" +
"id='" + id + '\'' +
'}';
}
}
@Configurable
@ComponentScan(value = "com.hrh")
public class BeanConfig {
@Primary
@Bean("userDao1")
public UserDao userDao() {
UserDao userDao = new UserDao();
userDao.setId("2");
return userDao;
}
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
UserService person = context.getBean(UserService.class);
person.printf();
//UserDao userDao = context.getBean(UserDao.class);
UserDao userDao =(UserDao) context.getBean("userDao1");
System.out.println(userDao);@Resource&@Inject:Java规范
@Resource:只按照属性名称进行装配,可以使用@Resource(name = "")装配指定id;不支持@Primary的使用,即使用该注解是无效的;
@Inject:支持自动装配,和@Autowired功能一样,支持@Primary的使用;没有required = false属性;
Aware注入Spring底层组件&原理
自定义组件使用Spring容器底层的一些组件(ApplicationContext、BeanFactory...),实现xxxAware
public class Color implements ApplicationContextAware {
private ApplicationContext applicationContext;
//获取容器并赋值给当前类
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}xxxAware使用对应的xxxAwareProcessor进行处理:利用后置处理器在类初始化时注入组件
//bean:获得实现了ApplicationContextAware接口的类,即Color
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//类型判断
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
} AccessControlContext acc = null; if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
} if (acc != null) {
//权限检查
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);//转换并注入组件
} return bean;
} private void invokeAwareInterfaces(Object bean) {
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);
}
if (bean instanceof ApplicationContextAware) {
//给当前类注入ApplicationContext
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
@Profile:指定组件在哪个环境的情况下才能被注册到容器中
- 加了环境标识的bean,只有在指定环境才能被注册到容器中,默认是default环境
- 写在配置类上,只有是指定环境整个配置类里面的所有配置才能生效
- 没有环境标识的bean在任何环境下都会被注册到容器中
@PropertySource("classpaht:/db.properties")
@Configuration
public class BeanProfileConfig {
@Value("${db.user}")
private String user;
@Value("${db.driverClass}")
private String driverClass; @Profile("test")
@Bean
public DataSource TestDateSource(@Value("${db.password}") String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setDriverClass(driverClass);
return dataSource;
} @Profile("dev")
@Bean
public DataSource DevDateSource(@Value("${db.password}") String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dev");
dataSource.setDriverClass(driverClass);
return dataSource;
} @Profile("pro")
@Bean
public DataSource ProDateSource(@Value("${db.password}") String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/pro");
dataSource.setDriverClass(driverClass);
return dataSource;
}
}
/**
* 1.使用命令行动态参数:在虚拟机参数位置加载 -Dspring.profiles.active=test
* 2.代码方式:创建无参容器,设置激活环境
*/
//创建容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//设置需要激活的环境
context.getEnvironment().setActiveProfiles("test");
//注册主配置类
context.register(BeanProfileConfig.class);
//启动刷新容器
context.refresh();
Spring笔记(2) - 生命周期/属性赋值/自动装配及部分源码解析的更多相关文章
- 你还不知道Vue的生命周期吗?带你从Vue源码了解Vue2.x的生命周期(初始化阶段)
作者:小土豆biubiubiu 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.im/user/58c61b4361ff4b005d9e8 ...
- Java基础知识强化之集合框架笔记11:Collection集合之迭代器的原理及源码解析
1. 迭代器为什么不定义成一个类,而是定义为一个接口 ? 答:假设迭代器定义的是一个类,这样我们就可以创建该类的对象,调用该类的方法来实现集合的遍历.但是呢? 我们想想,Java中提供了很多的集合类 ...
- Spring系列(三):Spring IoC源码解析
一.Spring容器类继承图 二.容器前期准备 IoC源码解析入口: /** * @desc: ioc原理解析 启动 * @author: toby * @date: 2019/7/22 22:20 ...
- springboot源码解析-管中窥豹系列之自动装配(九)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- 【spring 注解驱动开发】spring对象的生命周期
尚学堂spring 注解驱动开发学习笔记之 - 生命周期 生命周期 1.生命周期-@Bean指定初始化和销毁方法 2.生命周期-InitializingBean和DisposableBean 3.生命 ...
- Spring Bean的生命周期,《Spring 实战》书中的官方说法
连着两天的面试 ,都问到了 Spring 的Bean的生命周期,其中还包括 昨晚一波阿里的电话面试.这里找到了Spring 实战中的官方说法.希望各位要面试的小伙伴记住,以后有可能,或者是有时间 去看 ...
- Spring学习手札(四)谈谈Spring Bean的生命周期及作用域
在Spring中,那些组成应用程序的主体以及由Spring IoC容器所管理的对象,被称之为Bean.Bean与应用程序中其他对象(比如自己创建类)的区别就是,Bean是由IoC容器创建于销毁的.在S ...
- Spring动态代理及Spring Bean的生命周期
数组添加值 public class DiTest { /** * 数组 */ private String [] arrays; /** * List:集合 */ private List<I ...
- Spring(三)--Spring bean的生命周期
Spring bean的生命周期 ApplicationContext Bean生命周期流程 1.需要的实体类 ackage com.xdf.bean; import org.springframew ...
随机推荐
- java实现 洛谷 P1056 排座椅
import java.util.Arrays; import java.util.Map.Entry; import java.util.Scanner; import java.util.Tree ...
- java实现第六届蓝桥杯打印菱形
打印菱形 给出菱形的边长,在控制台上打印出一个菱形来. 为了便于比对空格,我们把空格用句点代替. 当边长为8时,菱形为: .......* ......*.* .....*...* ....*.... ...
- Jmeter之Json提取器详解(史上最全)
参考资料:https://www.bbsmax.com/A/D854lmBw5E/ Jsonpath在线测试:http://jsonpath.com/ 实际工作中用到的一些场景: 提取某个特定的值 提 ...
- python自学Day03(自学书籍python编程从入门到实践)
第4章 操作列表 只需要几行代码无论列表有多长,循环都能够让我对列表的每个元素都采取一个或一系列相同的措施,从而高效的处理任何长度的列表. 4.1 遍历整个列表 对列表中每个元素都拿出来,进行一个或者 ...
- iOS-地图定位 && 解码与反解码
前段时间,公司开发的App用到了地图和定位,所以记录一下,作为回顾总结. 对于地图和定位,苹果公司提供给了两个框架: MapKit:用于地图展示 Core Location ...
- HDU - 2546 饭卡 题解
题目大意 电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额.如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够) ...
- String 的格式化
使用场景 用于生成redis等key-value 结构的key的格式化,方便管理 eg: String.format(RedisKeys.PURCHASE_ADD_BABY_LOCK,form.get ...
- 用Springboot干掉IBM的WAS-为公司省点钱
1 那一夜,你伤害了我 今夜的雨下得凉快,小南睡得正香,突然收到远洋运维小周的电话:Hello, Are you OK? WAS有issue,快起来help me! 只见小南登陆WAS机,查看了机器日 ...
- <OPTEE>Trusted Application结构分析
最近又开始和Trusted Zone打起了交道,需要把Linaro开发的开源安全系统optee os移植到实验室的老板子上.不过导师要求我先开发一个应用,在普通环境和安全环境分别有一个程序,称为hos ...
- MATLAB读取和保存nifti文件
介绍 分析核磁数据时,数据的读取和保存是两个基本的操作.虽然大部分工具包都对这些功能进行了封装,但是如果你不了解如何使用这些工具包或者说当前的任务太简单不值得去使用这些庞大的工具包的时候就需要我们自己 ...