IOC容器
IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的权利全是交由用户来控制的,现在这种权利交由Spring容器控制,容器会根据配置文件去创建各个实例之间的依赖关系,实现了对象与对象之间的松耦合。实现原理是通过Java的反射来动态生成对象,注入方式一共有三种,分别是构造器注入,setter注入。
容器启动及配置类加载流程
- 容器的启动
首先,调用BeanDefinitionReader加载配置文件,将内容映射到BeanDefinition中,解析配置文件,并将类型信息存储到BeanDefinition,交给BeanDefinitionRegistry管理,最后注册到BeanFactory。 - Bean实例化
创建过程
- 实例化bean对象,以及设置bean属性;
- 如果通过Aware接口声明了依赖关系,则会注入Bean对容器基础设施层面的依赖,Aware接口是为了感知到自身的一些属性。容器管理的Bean一般不需要知道容器的状态和直接使用容器。但是在某些情况下是需要在Bean中对IOC容器进行操作的。这时候需要在bean中设置对容器的感知。SpringIOC容器也提供了该功能,它是通过特定的Aware接口来完成的。 比如BeanNameAware接口,可以知道自己在容器中的名字。 如果这个Bean已经实现了BeanFactoryAware接口,可以用这个方式来获取其它Bean。 (如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名字。 如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。 如果Bean实现了BeanFactoryAware接口,调用setBeanFactory()方法,传入BeanFactory对象的实例。)
- 紧接着会调用BeanPostProcess的前置初始化方法postProcessBeforeInitialization,主要作用是在Spring完成实例化之后,初始化之前,对Spring容器实例化的Bean添加自定义的处理逻辑。有点类似于AOP。
- 如果实现了BeanFactoryPostProcessor接口的afterPropertiesSet方法,做一些属性被设定后的自定义的事情。
- 调用Bean自身定义的init方法,去做一些初始化相关的工作。
- 调用BeanPostProcess的后置初始化方法,postProcessAfterInitialization去做一些bean初始化之后的自定义工作。
- 完成以上创建之后就可以在应用里使用这个Bean了。
销毁过程
当Bean不再用到,便要销毁 。
自动装配的方式
当 bean 在 Spring 容器中组合在一起时,它被称为装配或 bean 装配。 Spring 容器需要知道需要什么 bean 以及容器应该如何使用依赖注入来将 bean 绑定在一起,同时装配 bean。
Spring 容器能够自动装配 bean。也就是说,可以通过检查 BeanFactory 的内容让 Spring 自动解析 bean 的协作者。
- no:不进行自动装配,手动设置Bean的依赖关系。
- byName:根据Bean的名字进行自动装配。
- byType:根据Bean的类型进行自动装配。
- constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误。
- autodetect:如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配。
缺点
- 覆盖的可能性 - 您始终可以使用 和 设置指定依赖项,这将覆盖自动装配。
- 基本元数据类型 - 简单属性(如原数据类型,字符串和类)无法自动装配。
- 令人困惑的性质 - 总是喜欢使用明确的装配,因为自动装配不太精确。
IOC和DI
IoC叫控制反转,是Inversion of Control的缩写,通俗的说就是我们不用自己创建实例对象,这些都交给Spring的bean工厂帮我们创建管理。这也是Spring的核心思想,通过面向接口编程的方式来是实现对业务组件的动态依赖。这就意味着IOC是Spring针对解决程序耦合而存在的。DI(Dependency Injection)叫依赖注入,是对IoC更简单的诠释。DI即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。
依赖注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常使用构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入是更好的选择,setter注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。
构造器注入和Setter注入的区别
构造函数注入 | Setter注入 |
---|---|
没有部分注入 | 有部分注入 |
不会覆盖 setter 属性 | 会覆盖 setter 属性 |
任意修改都会创建一个新实例 | 任意修改不会创建一个新实例 |
适用于设置很多属性 | 适用于设置少量属性 |
BeanFactory和ApplicationContext的区别
- BeanFactory
BeanFactory是spring中比较原始,比较古老的Factory。因为比较古老,所以BeanFactory无法支持spring插件,例如:AOP、Web应用等功能。 - ApplicationContext
ApplicationContext是BeanFactory的子接口,因为古老的BeanFactory无法满足不断更新的spring的需求,于是ApplicationContext就基本上代替了BeanFactory的工作,以一种更面向框架的工作方式以及对上下文进行分层和实现继承,并在这个基础上对功能进行扩展:- MessageSource, 提供国际化的消息访问;
- 资源访问(如URL和文件);
- 事件传递;
- Bean的自动装配;
- 各种不同应用层的Context实现。
区别:
BeanFactory | ApplicationContext |
---|---|
不支持AOP、WEB | 支持AOP、WEB |
懒汉式加载Bean | 饿汉式加载单例 |
使用语法显式提供资源对象 | 自己创建和管理资源对象 |
不支持国际化 | 支持国际化 |
不支持基于依赖的注解 | 支持基于依赖的注解 |
BeanFactory的优缺点:
- 优点:应用启动的时候占用资源很少,对资源要求较高的应用,比较有优势;
- 缺点:运行速度会相对来说慢一些。而且有可能会出现空指针异常的错误,而且通过Bean工厂创建的Bean生命周期会简单一些。
ApplicationContext的优缺点:
- 优点:所有的Bean在启动的时候都进行了加载,系统运行的速度快;在系统启动的时候,可以发现系统中的配置问题。
- 缺点:把费时的操作放到系统启动中完成,所有的对象都可以预加载,缺点就是内存占用较大。
创建Bean的几种方式
- 使用xml配置(不利于对象管理)
<bean id="xxxx" class="xxxx.xxxx"/>
- 使用注解@Component,@Service,@Controller,@Repository
@Component:侧重于通用的Bean类;
@Service:标识该类用于业务逻辑;
@Controler:标识该类为Spring MVC的控制器类;
@Repository:标识该类是一个实体类,只有属性和Setter,Getter。它为 DAO 提供了额外的好处。它将 DAO 导入 IOC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。 - 使用@Bean注解
- 使用@Import
@Import(User.class)
public class MicroblogUserWebApplication {
public static void main(String args[]) {
SpringApplication.run(MicroblogUserWebApplication.class, args);
}
}
手动注入 ```java @Component public class LocationRegister implements BeanFactoryAware {
@Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory)beanFactory;
//方式1 Location location = new Location(); listableBeanFactory.registerSingleton(Location.class.getName(),location);
//方式2 BeanDefinition locationBeanDefinition = new RootBeanDefinition(Location.class); listableBeanFactory.registerBeanDefinition(Location.class.getName(),locationBeanDefinition); } }
<a name="QjAXS"></a>
#### Spring中的单例bean的线程安全问题
当多个用户同时请求一个服务时,容器会给每一个请求分配一个线程,这时多个线程会并发执行该请求对应的业务逻辑(成员方法),此时就要注意了,如果该处理逻辑中有对单例状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题。 **线程安全问题都是由全局变量及静态变量引起的。** 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全.<br />**无状态bean和有状态bean**
- 有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。
- 无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象 .不能保存数据,是不变类,是线程安全的。
在spring中无状态的Bean适合用不变模式,就是单例模式,这样可以共享实例提高性能。有状态的Bean在多线程环境下不安全,适合用[Proto](/jump/super-jump/word?word=Proto)type原型模式。 Spring使用ThreadLocal解决线程安全问题。如果你的Bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全 。
<a name="77b59385"></a>
#### 实例化Bean的源码分析
以单例为例:
<a name="56a51423"></a>
##### DefaultSingletonBeanRegistry#getSingleton()
```java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
...
try {
// 从单例工厂获取实例对象
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
...
}
...
return singletonObject;
}
}
主要通过singletonFactory.getObject()方法来获取实例Bean,其中,getObject()主要调用了AbstractBeanFactory的doGetBean()方法。
AbstractBeanFactory#doGetBean()
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
...
}
这段代码主要是调用了createBean()方法。
AbstractAutowireCapableBeanFactory#createBean
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...
// 根据设置的class属性或className来解析得到class引用
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
...
try {
// 处理InstantiationAwareBeanPostProcessor
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
...
}
try {
// 创建bean实例
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
...
return beanInstance;
}
catch (BeanCreationException ex) {
...
}
}
createBean解析class并得到class的引用,并做了一些前置后置处理器的初始化,随后会进入doCreateBean()。
AbstractAutowireCapableBeanFactory#doCreateBean()
- 如果是单例,尝试从缓存中获取 bean 的包装器 BeanWrapper
- 如果不存在对应的 Wrapper,则说明 bean 未被实例化,创建 bean 实例
- 应用 MergedBeanDefinitionPostProcessor
- 检查是否需要提前曝光,避免循环依赖
- 初始化 bean 实例
- 再次基于依存关系验证是否存在循环依赖
- 注册 DisposableBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
// 如果是单例,尝试获取对应的Bean包装器
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
/*
* 说明对应的bean还没有创建,用对应的策略(工厂方法、构造函数)创建bean实例,以及简单初始化
*
* 将beanDefinition转成BeanWrapper,大致流程如下:
* 1. 如果存在工厂方法,则使用工厂方法初始化
* 2. 否则,如果存在多个构造函数,则根据参数确定构造函数,并利用构造函数初始化
* 3. 否则,使用默认构造函数初始化
*/
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
// 获取class引用
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 应用MergedBeanDefinitionPostProcessor
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
...
}
mbd.postProcessed = true;
}
}
// 检查是否需要提前曝光,避免循环依赖
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
...
// 添加一级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 初始化Bean实例
Object exposedObject = bean;
try {
// 属性填充
populateBean(beanName, mbd, instanceWrapper);
// 调用初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
...
}
// 在此基于依存关系验证是否存在循环依赖
if (earlySingletonExposure) {
// 提前曝光
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 检测到循环依赖
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 获取依赖的bean name
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
// 检测依赖,记录未完成创建的bean
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// 不为空说明bean依赖的bean没有创建,存在循环依赖
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(...);
}
}
}
}
//注册DisposableBean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
...
}
return exposedObject;
}
AbstractAutowireCapableBeanFactory#populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
...
}
boolean continueWithPropertyPopulation = true;
// 给InstantiationAwareBeanPostProcessors最后一次机会在注入属性前改变bean实例
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
// 如果处理器指明不需要再继续执行属性注入,则返回
if (!continueWithPropertyPopulation) {
return;
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// autowire by name or autowire by type
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// autowire by name
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// autowire by type
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
// 在属性注入前应用实例化后置处理器
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 调用后置处理器的postProcessPropertyValues方法
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
// 执行属性注入
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
该方法会执行 InstantiationAwareBeanPostProcessor 后置处理器的 postProcessAfterInstantiation 方法逻辑,从而实现对完成实例化且还没有注入属性值的对象进行最后的更改。
如果我们在 postProcessAfterInstantiation 指明不需要执行后续的属性注入过程,则方法到此结束;否则方法会检测当前的注入类型,是 byName 还是 byType,并调用相应的注入逻辑获取依赖的 bean,加入属性集合中。然后方法会调用 InstantiationAwareBeanPostProcessor 后置处理器的 postProcessPropertyValues 方法,实现在将属性值应用到 bean 实例之前的最后一次对属性值的更改,同时会依据配置执行依赖检查,以确保所有的属性都被赋值。
接下来我们看看真正的属性赋值操作。
AbstractAutowireCapableBeanFactory#applyPropertyValues
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
...
// 获取对应的解析器
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// 深度拷贝
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
// 遍历属性,将属性转换成对应类的属性类型
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
// 执行类型转换
String propertyName = pv.getName();
Object originalValue = pv.getValue();
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
try {
// 设置值
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
...
}
}
使用深拷贝完成了属性的注入。属性注入完成后执行的是initializeBean()方法。
AbstractAutowireCapableBeanFactory#initializeBean
- 激活 bean 实现的 Aware 类:BeanNameAware, BeanClassLoaderAware, BeanFactoryAware
- 应用 BeanPostProcessor 的 postProcessBeforeInitialization
- 激活用户自定义的 init-method 方法,以及常用的 afterPropertiesSet 方法
- 应用 BeanPostProcessor 的 postProcessAfterInitialization
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 1. 激活bean实现的Aware类:BeanNameAware, BeanClassLoaderAware, BeanFactoryAware
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
// 2. 应用 BeanPostProcessor 的 postProcessBeforeInitialization
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 3. 激活用户自定义的 init-method 方法,以及常用的 afterPropertiesSet 方法
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
// 4. 应用 BeanPostProcessor 的 postProcessAfterInitialization
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
总结
首先,从Singleton工厂获取对象,随后进入createBean()方法,执行相关前置和后置处理器的初始化;处理完成后,调用doCrateBean的createBeanInstance进行Bean实例化操作;通过populateBean和applyPropertyValues进行属性注入,然后使用initializeBean激活Bean实现的Aware类,并检查循环依赖相关的逻辑,如果有必要,还会注册DisposableBean。
Spring中出现同名Bean怎么办
- 同一个配置文件内同名的Bean,以最上面定义的为准
- 不同配置文件中存在同名Bean,后解析的配置文件会覆盖先解析的配置文件
- 同文件中ComponentScan和@Bean出现同名Bean。同文件下@Bean的会生效,@ComponentScan扫描进来不会生效。通过@ComponentScan扫描进来的优先级是最低的,原因就是它扫描进来的Bean定义是最先被注册的
循环依赖
循环依赖:当Bean A依赖于Bean B时,而Bean B也正好依赖于Bean A。
spring对循环依赖的处理有三种情况: ①构造器的循环依赖:这种依赖spring是处理不了的,直 接抛出BeanCurrentlylnCreationException异常。 ②单例模式下的setter循环依赖:通过“三级缓存”处理循环依赖。 ③非单例循环依赖:无法处理。
Spring单例对象初始化主要步骤如下:
- createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象;
- populateBean:填充属性,这一步主要是多bean的依赖属性进行填充;
- initializeBean:调用spring xml中的init 方法。
循环依赖主要发生在第一、二步,分别是构造器循环依赖和field循环依赖。在这里,引入了一个三级缓存的概念,源码在DefaultSingletonBeanRegistry类中:
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
三级缓存从里到外分别是:
- singletonFactories : 单例对象工厂的cache;
- earlySingletonObjects :提前曝光的单例对象的Cache;
- singletonObjects:单例对象的cache。
具体获取Bean的代码在DefaultSingletonBeanRegistry的getSingleton()方法中:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先从最外层缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
那么一级缓存是什么时候添加的呢,细心的读者一定可以发现,在doCreateBean()方法中,createBeanInstance之后,属性注入之前,有一步:addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
,只要完成了实例化,就直接曝光,这就是所谓的早期引用概念。
值得注意的是,早期引用只能解决Setter注入的循环依赖问题,对于构造器注入和多实例的循环依赖问题是没有办法解决的。可以使用@Lazy注解进行懒加载来解决。
前置后置处理器
具体使用例子如下:
public class InitHelloWorld implements BeanPostProcessor{
public Object postProcessBeforeInitialization(Object bean,String beanName) {
System.out.println("BeforeInitialization:"+beanName);
return bean; // you can return any other object as well
}
public Object postProcessAfterInitialization(Object bean,String beanName) {
System.out.println("AfterInitialization:"+beanName);
return bean; // you can return any other object as well
}
}
首先需要实现BeanPostProcessor接口,然后重写前置和后置逻辑,最后需要在xml文件中进行配置:
<bean class = "com.lamarsan.InitHelloWorld"></bean>
AOP
Spring AOP是面向切面编程,它的单元是切面,我们可以对切面做一些增强,同时它有利于代码的维护。AOP的实现方式主要有基于jdk的动态代理以及基于cglib的动态代理,我们可以用基于xml配置以及AspectJ注解来实现Spring AOP。好处是减少重复代码,提高开发效率,并且便于维护。
相关概念术语
- 连接点(Joinpoint)
程序执行的某个特定位置(如:某个方法调用前、调用后,方法抛出异常后)。Spring仅支持方法的连接点。 - 增强(Advice)
增强是织入到目标类连接点上的一段程序代码。 - 引介(Introduction)
引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。 - 切点(Pointcut)
查询条件,一个切点可以匹配多个连接点。Spring AOP的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点。 - 切面(Aspect)
切面是由切点和增强(引介)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。 - 织入(Weaving)
织入是将增强添加到目标类具体连接点上的过程,AOP有三种织入方式:- 编译期织入:需要特殊的Java编译期(例如AspectJ的ajc);
- 装载期织入:要求使用特殊的类加载器,在装载类的时候对类进行增强;
- 运行时织入:在运行时为目标类生成代理实现增强。
Spring采用了动态代理的方式实现了运行时织入,而AspectJ采用了编译期织入和装载期织入的方式。
AOP的原理
AOP代理主要分为静态代理和动态代理。
- 静态代理
静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。通常使用AspectJ的编译时增强实现AOP,AspectJ是静态代理的增强,所谓的静态代理就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强。 动态代理
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。
JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。Spring事务隔离级别和事务传播属性
隔离级别
DEFAULT(默认),使用数据库默认的隔离级别
- READ_UNCOMMITTED(读未提交)
- READ_COMMITTED(读已提交)
- REPEATABLE_READ(可重复读)
-
传播属性
REQUIRED(默认)
如果存在一个事务,则支持当前事务,没有就开启一个新的事务。- REQUIRES_NEW
新建一个事务,如果当前存在事务,就挂起。 - MANDATORY
支持当前事务,如果没有事务就抛出异常。 - NEVER
以非事务方式运行,如果存在事务就抛出异常。 - NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就挂起。 - SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。 NESTED(嵌套事务)
支持当前事务,新增Savepoint,与当前事务同步提交或回滚。Spring声明式事务原理
当声明了@Transaction之后,首先会使用拦截器TransactionInterceptor进行拦截,调用invoke,然后调用父类的invokeWithinTransaction方法:
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
原理
在应用系统调用声明@Transactional 的目标方法时,Spring Framework ,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。
失效原因
- @Transactional注解应用到非public方法(除非特殊配置,例如使用AspectJ 静态织入实现 AOP);
- 自调用,因为@Transactional是基于动态代理实现的;
- 异常在代码中被你自己try catch了;
- 异常类型不正确,默认只支持RuntimeException和Error,不支持检查异常;
- 事务传播配置不符合业务逻辑。
由于基于动态代理实现(实现接口),因此修饰接口的必须是public类型,非public类型可以用AspectJ。
Spring事务管理有哪些优点
- 它提供了跨不同事务api(如JTA、JDBC、Hibernate、JPA和JDO)的一致编程模型。
- 它为编程事务管理提供了比JTA等许多复杂事务API更简单的API。
- 它支持声明式事务管理。
- 它很好地集成了Spring的各种数据访问抽象。
Spring中的设计模式
- 简单工厂模式
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类,不属于23种设计模式之一。Spring 中的 BeanFactory 就是简单工厂模式的体现,根据传入一个唯一的标识来获得 Bean 对象。 - 工厂方法模式
应用程序将对象的创建及初始化职责交给工厂对象。 一般情况下,应用程序有自己的工厂对象来创建 Bean。 - 单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。 Spring 中的单例模式完成了后半句话,即提供了全局的访问点 BeanFactory。但没有从构造器级别去 控制单例,这是因为 Spring 管理的是是任意的 Java 对象。 Spring 下默认的 Bean 均为单例。 - 原型模式
原型模式就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。如在IOC为Bean注入属性的时候,会使用深拷贝,就是一个原型模式的体现。 - 代理模式
为其他对象提供一种代理以控制对这个对象的访问。Spring 的 Proxy 模式在 AOP 中有体现,比如 JdkDynamicAopProxy 和 Cglib2AopProxy。 - 策略模式
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换,使最终结果是固定的。Spring 中在实例化对象的时候用到 Strategy 模式,在 SimpleInstantiationStrategy 有使用。 - 模板方法模式
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Spring 中的 JdbcTemplate就是用的模板模式。 - 适配器模式
注重转换。前端控制器DispatcherServlet可以把它理解为适配器模式中的Client,它的主要作用在于通过处理映射器(HandlerMapper)来找到相应的Handler,然后通过适配器去找到对应的Controller,并执行Controller中相应的方法并返回ModelAndView。如果不使用适配器接口,就要多许多if,else判断了,违反开闭原则。 - 装饰器模式
主要用于扩展功能。所有以Wrapper和Decorator结尾的类名都是。 - 观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象 都得到通知并被自动更新。Spring 中 Observer 模式常用的地方是 Listener 的实现。如 ApplicationListener。