1.事务
1.1.事务传播
同一个类中 事务A调非事务B B抛异常 AB事务生效(具有传播性)
同一个类中 事务A调非事务B A抛异常 AB事务生效
也就是主方法加了事务注解 则方法内调用的其他本类方法无需加事务注解,
发生异常时可以保证事务的回滚
最常用
1.2.代理
需要用到代理的是,非事务A调用事务B,如果想让B的事务生效,需要用代理模式
2.循环依赖
@Validated 底层为AOP机制,注解会导致循环依赖问题(即使加了spring:main:allow-circular-references: true)。
3.spring扩展点
3.1重写afterPropertiesSet()方法
AbstractAutowireCapableBeanFactory#initializeBean()方法中会执行我们重写的方法。
3.2.@PostConstruct
AbstractAutowireCapableBeanFactory#initializeBean()方法中会执行我们加了@PostConstruct注解的方法。
是CommonAnnotationBeanPostProcessor执行的,方法在他的父类InitDestroyAnnotationBeanPostProcessor
也就是在3.1方法的上面
3.3.initMethod
3.4.BeanPostProcessor接口
重写这两个方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
AbstractAutowireCapableBeanFactory#initializeBean()方法中会执行我们重写的方法。
分别在invokeInitMethods方法的前后执行
也可以实现bean创建后的逻辑,但是要注意类型判断,不然每个bean(包括系统级的bean)初始化时都会调用我们重写的方法。
4.bean的作用域
4.1.单例
singleton(默认)
所有线程共享,对于有状态的单例bean存在线程安全问题
有状态的单例bean(它是有存储能力的。也就是说至少有一个属性来标识它目前的状态,意思就是你想在代码里用一个变量存储一个值,在代码运行期间想要实时获取,且不同用户值不同,例如租户id)
public class TestManagerImpl implements TestManager{
private User user;
public void deleteUser(User e) throws Exception {
user = e ; //1
prepareData(e);
}
public void prepareData(User e) throws Exception {
user = getUserByID(e.getId()); //2
.....
//使用user.getId(); //3
.....
.....
}
}
//不同对象的行为不同
如果该Bean配置为singleton,会出现什么样的状况呢?
如果有2个用户访问,都调用到了该Bean.
假定为user1,user2
当user1 调用到程序中的1步骤的时候,该Bean的私有变量user被付值为user1
当user1的程序走到2步骤的时候,该Bean的私有变量user被重新付值为user1_create
理想的状况,当user1走到3步骤的时候,私有变量user应该为user1_create;
但如果在user1调用到3步骤之前,user2开始运行到了1步骤了,由于单态的资源共享,则私有变量user被修改为user2
这种情况下,user1的步骤3用到的user.getId()实际用到是user2的对象。(我的理解是配置成singleton会造成资源混乱问题-对于有状态的bean)
正确使用方式
/**
* 当前租户编号
*/
private static final ThreadLocal<Long> TENANT_ID = new TransmittableThreadLocal<>();
/**
* 获得租户编号。
*
* @return 租户编号
*/
public static Long getTenantId() {
return TENANT_ID.get();
}
public static void setTenantId(Long tenantId) {
TENANT_ID.set(tenantId);
}
4.2多例
prototype
每次都是获取到新的对象,线程安全
定义方式