IOC反转控制:将之前程序中需要手动创建对象的操作,交由Spring框架来实现,创建对象的操作被反转到了Spring框架。对象的生命周期由Spring来管理,直接从Spring那里去获取一个对象
DI依赖注入:Spring框架创建Bean对象时,动态的将依赖对象注入到Bean组件中,实现依赖对象的注入
依赖查找是主动或手动的依赖查找方式,通常需要依赖容器或标准API实现。而依赖注入则是手动或自动依赖绑定的方式,无需依赖特定的容器和API
1)BeanFactory默认采用延迟初始化(lazy-load),第一次getBean时才会初始化Bean;ApplicationContext是会在加载配置文件时初始化Bean
2)BeanFactory提供完整的IOC服务支持;ApplicationContext是对BeanFactory扩展,它可以进行国际化处理、事件传递和Bean自动装配以及各种不同应用层的Context实现
1)、使用类构造器实例化(默认无参数)
<bean id="accountService" class="com.hand.demo.service.AccountServiceImpl"/>
2)、使用静态工厂方法实例化(简单工厂模式)
public class StaticFactory {
public static IAccountService getAccountService() {
return new AccountServiceImpl();
}
}
<bean id="accountService" class="com.hand.demo.factory.StaticFactory" factory-method="getAccountService"/>
3)、使用实例工厂方法实例化(工厂方法模式)
public class InstanceFactory {
public IAccountService getAccountService() {
return new AccountServiceImpl();
}
}
<bean id="instanceFactory" class="com.hand.demo.factory.InstanceFactory"/>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"/>
1)、setter方法注入
public class User {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
public class UserHolder {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "UserHolder{" +
"user=" + user +
'}';
}
}
1)Xml配置
setter-injection.xml:
<bean id="userHolder" class="com.hand.demo.injection.UserHolder">
<property name="user" ref="user"/>
bean>
<bean id="user" class="com.hand.demo.domain.User">
<property name="id" value="1"/>
<property name="name" value="Jack"/>
bean>
public class XmlSetterInjectionDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String xmlResourcePath = "classpath:/setter-injection.xml";
//加载Xml资源、解析并且生成BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//依赖查找并且创建Bean
UserHolder userHolder = beanFactory.getBean(UserHolder.class);
System.out.println(userHolder);
}
}
2)Java注解
setter-injection.xml:
<bean id="user" class="com.hand.demo.domain.User">
<property name="id" value="1"/>
<property name="name" value="Jack"/>
bean>
public class AnnotationSetterInjectionDemo {
public static void main(String[] args) {
//创建ApplicationContext容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/setter-injection.xml";
//加载Xml资源、解析并且生成BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//注册配置类
applicationContext.register(AnnotationSetterInjectionDemo.class);
//启动Spring应用上下文
applicationContext.refresh();
//依赖查找并且创建Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
//关闭Spring应用上下文
applicationContext.close();
}
@Bean
public UserHolder userHolder(User user) {
UserHolder userHolder = new UserHolder();
userHolder.setUser(user);
return userHolder;
}
}
3)API配置元信息
setter-injection.xml:
<bean id="user" class="com.hand.demo.domain.User">
<property name="id" value="1"/>
<property name="name" value="Jack"/>
bean>
public class ApiSetterInjectionDemo {
public static void main(String[] args) {
//创建ApplicationContext容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//生成UserHolder的BeanDefinition
BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
//注册UserHolder的BeanDefinition
applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/setter-injection.xml";
//加载Xml资源、解析并且生成BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动Spring应用上下文
applicationContext.refresh();
//依赖查找并且创建Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
//关闭Spring应用上下文
applicationContext.close();
}
/**
* 为UserHolder生成BeanDefinition
*
* @return
*/
public static BeanDefinition createUserHolderBeanDefinition() {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
builder.addPropertyReference("user", "user");
return builder.getBeanDefinition();
}
}
2)、构造器注入
1)Xml配置
constructor-injection.xml:
<bean id="userHolder" class="com.hand.demo.injection.UserHolder">
<constructor-arg name="user" ref="user"/>
bean>
<bean id="user" class="com.hand.demo.domain.User">
<property name="id" value="1"/>
<property name="name" value="Jack"/>
bean>
2)Java注解
public class AnnotationConstructorInjectionDemo {
public static void main(String[] args) {
//创建ApplicationContext容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/setter-injection.xml";
//加载XML资源、解析并且生成BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//注册配置类
applicationContext.register(AnnotationConstructorInjectionDemo.class);
//启动Spring应用上下文
applicationContext.refresh();
//依赖查找并且创建Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
//关闭Spring应用上下文
applicationContext.close();
}
@Bean
public UserHolder userHolder(User user) {
UserHolder userHolder = new UserHolder(user);
return userHolder;
}
}
3)API配置元信息
public class ApiConstructorInjectionDemo {
public static void main(String[] args) {
//创建ApplicationContext容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//生成UserHolder的BeanDefinition
BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
//注册UserHolder的BeanDefinition
applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/setter-injection.xml";
//加载XML资源、解析并且生成BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动Spring应用上下文
applicationContext.refresh();
//依赖查找并且创建Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
//关闭Spring应用上下文
applicationContext.close();
}
/**
* 为UserHolder生成BeanDefinition
*
* @return
*/
public static BeanDefinition createUserHolderBeanDefinition() {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
builder.addConstructorArgReference("user");
return builder.getBeanDefinition();
}
}
3)、字段注入
4)、方法注入
public class AnnotationMethodInjectionDemo {
private UserHolder userHolder;
private UserHolder userHolder2;
@Autowired
public void initUserHolder(UserHolder userHolder) {
this.userHolder = userHolder;
}
@Resource
public void initUserHolder2(UserHolder userHolder2) {
this.userHolder2 = userHolder2;
}
public static void main(String[] args) {
//创建ApplicationContext容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/setter-injection.xml";
//加载XML资源、解析并且生成BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//注册配置类
applicationContext.register(AnnotationMethodInjectionDemo.class);
//启动Spring应用上下文
applicationContext.refresh();
//依赖查找 AnnotationMethodInjectionDemo Bean
AnnotationMethodInjectionDemo demo = applicationContext.getBean(AnnotationMethodInjectionDemo.class);
System.out.println(demo.userHolder == demo.userHolder2);//true
//关闭Spring应用上下文
applicationContext.close();
}
@Bean
public UserHolder userHolder(User user) {
UserHolder userHolder = new UserHolder(user);
return userHolder;
}
}
Spring IOC容器实现分为两个阶段:容器启动阶段和Bean实例化阶段
1)、容器启动阶段
容器依赖工具类BeanDefinitionReader对加载的Configuration MetaData进行解析和分析,并将分析后的信息编组为相应的BeanDefinition,最后把这些保存了Bean定义必要信息的BeanDefinition,注册到相应的BeanDefinitionRegistry
1)容器的扩展点:BeanFactoryPostProcessor
BeanFactoryPostProcessor可以对Bean配置元数据进行操作。也就是说,Spring容器允许BeanFactoryPostProcessor读取指定Bean的配置元数据(BeanDefinition),并可以在Bean被实例化之前修改它
2)、Bean实例化阶段
经过第一阶段,所有的Bean定义信息都通过BeanDefinition的方式注册到了BeanDefinitionRegistry中,当某个请求方法通过容器的getBean方法请求某个对象或者因依赖关系容器需要隐式地调用getBean方法时,就会触发Bean的实例化
隐式调用有如下两种情况:
getBean()
,对于本次请求的请求方是隐式的getBean()
只有当对应某个Bean定义的getBean()
方法第一次被调用时,不管是显示的还是隐式的,Bean实例化阶段的活动才会被触发,第二次被调用则会直接返回容器缓存的第一次实例化完的对象实例(多例模式除外)
1)Bean的实例化与BeanWrapper
容器内部实现采用策略模式来决定使用何种方式初始化Bean实例
InstantiationStrategy是实例化策略的抽象接口,其直接子类SimpleInstantiationStrategy实现了通过反射来实例化对象实例,但不支持方法注入方式的对象实例化
CglibSubclassingInstantiationStrategy继承了SimpleInstantiationStrategy的以反射方式实例化对象的功能,并通过CGLIB的动态字节码生成功能,可以动态生成某个类的子类,进而满足了方法注入所需的对象实例化需求。默认情况下,容器内部采用的是CglibSubclassingInstantiationStrategy
容器只要根据相应bean定义的BeanDefinition取得实例化信息,结合CglibSubclassingInstantiationStrategy以及不同的Bean定义类型,就可以返回实例化完成的对象实例。但是,不是直接返回构造完成的对象实例,而是以BeanWrapper对构造完成的对象实例进行包裹,返回相应的BeanWrapper实例
BeanWrapper接口有一个实现类BeanWrapperImpl,其作用就是对某个Bean进行包裹,然后对这个包裹的Bean进行操作,比如设置或者获取Bean的相应属性值,使用BeanWrapper对Bean实例操作很方便,可以免去直接使用反射API操作对象的繁琐
2)Aware接口
当对象实例化完成并且相关属性以及依赖设置完成之后,Spring容器会检查当前对象实例是否实现了一系列的以Aware命名结尾的接口定义。如果是,则将这些Aware接口定义中规定的依赖注入给当前对象实例。下面按照执行顺序进行介绍
BeanFactory中Aware接口:
ApplicationContext类型的容器在检测Aware接口并设置相关依赖的实现机制上,与以上几个接口处理方式有所不同,使用的是BeanPostProcessor方式
ApplicationContext中Aware接口:
3)容器的扩展点:BeanPostProcessor
BeanPostProcessor接口提供Spring Bean初始化前和初始化后的生命周期回调,分别对应postProcessBeforeInitialization和postProcessAfterInitialization方法,允许对Bean进行扩展甚至是替换
public interface BeanPostProcessor {
//在Bean初始化前调用
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
//在Bean初始化后调用
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
4)Bean初始化
afterPropertiesSet()
方法
的init-method属性指定方法名5)DisposableBean和destroy-method
destroy()
方法
的destroy-method属性指定方法名FactoryBean主要用来定制化Bean的创建逻辑,FactoryBean接口方法如下:
public interface FactoryBean<T> {
//返回这个FactoryBean所创建的对象
@Nullable
T getObject() throws Exception;
//返回这个FactoryBean所创建对象的类型
@Nullable
Class<?> getObjectType();
//返回FactoryBean所创建的对象是否为单例,默认返回true
default boolean isSingleton() {
return true;
}
}
假设我们定义了一个FactoryBean,名为myFactoryBean,当调用getBean("myFactoryBean")
方法时返回的并不是这个FactoryBean,而是这个FactoryBean所创建的Bean,如果想获取到这个FactoryBean需要在名字前面拼接&
,行如这种形式:getBean("&myFactoryBean")
public class MyFactoryBean implements FactoryBean<IAccountService> {
public IAccountService getObject() throws Exception {
System.out.println("执行创建Bean的逻辑");
return new AccountServiceImpl();
}
public Class<?> getObjectType() {
return IAccountService.class;
}
public boolean isSingleton() {
return true;
}
}
public interface IAccountService {
void saveAccount();
}
public class AccountServiceImpl implements IAccountService {
public AccountServiceImpl(){
System.out.println("AccountServiceImpl被创建出来了");
}
public void saveAccount() {
System.out.println("保存了账户");
}
}
<bean id="myFactoryBean" class="com.hand.demo.factorybean.MyFactoryBean"/>
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:bean.xml");
IAccountService as = (IAccountService) ac.getBean("myFactoryBean");
as.saveAccount();
执行结果:
执行创建Bean的逻辑
AccountServiceImpl被创建出来了
保存了账户
1)、什么是循环依赖
循环依赖指的是多个对象之间的依赖关系形成一个闭环
2)、Spring的所有对象都支持循环依赖吗?
单例模式下默认是支持的,但是如果通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException异常表示循环依赖;多例模式不支持
3)、怎么检测是否存在循环依赖
Bean在创建的时候可以给该Bean打标,如果递归调用回来发现正在创建中的话,即说明了循环依赖了
4)、案例
public class A {
private B b;
public void setB(B b) {
this.b = b;
}
}
public class B {
private A a;
public void setA(A a) {
this.a = a;
}
}
circular-dependence.xml:
<bean id="a" class="com.hand.demo.circularDependence.A">
<property name="b" ref="b"/>
bean>
<bean id="b" class="com.hand.demo.circularDependence.B">
<property name="a" ref="a"/>
bean>
//创建ApplicationContext容器
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"classpath:circular-dependence.xml");
A a = (A) applicationContext.getBean("a");
System.out.println(a);
5)、实现原理分析
Bean从实例化到依赖注入核心代码调用如下:
AbstractApplicationContext.refresh()
↓
↓
//实例化所有剩余的(非延迟初始化)单例
finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)
↓
↓
DefaultListableBeanFactory.preInstantiateSingletons()
↓
↓
//循环调用所有剩余的(非延迟初始化)单例的getBean()方法
AbstractBeanFactory.getBean(String name)
↓
↓
doGetBean(final String name, @Nullable final Class requiredType,
@Nullable final Object[] args, boolean typeCheckOnly)
↓
↓
//检查缓存中是否有手动注册的单例
DefaultSingletonBeanRegistry.getSingleton(String beanName) →→ getSingleton(String beanName, boolean allowEarlyReference)
↓
↓
DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory> singletonFactory)
↓
↓
//创建Bean实例
AbstractAutowireCapableBeanFactory.createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
↓
↓
doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
↓
↓
createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
↓
↓
//如果earlySingletonExposure是true,将单例对象的引用通过ObjectFactory保存下来,然后将该ObjectFactory缓存在三级缓存singletonFactories中
earlySingletonExposure == true →→ DefaultSingletonBeanRegistry.addSingletonFactory(String beanName, ObjectFactory> singletonFactory)
↓
↓
//执行依赖注入
populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
↓
↓
//初始化Bean,调用Spring xml中的init方法
initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
Bean的创建最为核心的三个方法:
循环依赖主要发生在第二步(populateBean),也就是field属性注入的处理
三级缓存核心逻辑:
创建Bean的时候Spring首先从一级缓存singletonObjects中获取。如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取,如果还是获取不到就从三级缓存singletonFactories中取(Bean调用构造函数进行实例化后,即使属性还未填充,就可以通过三级缓存向外提前暴露依赖的引用,根据对象引用能定位到堆中的对象,其原理是基于Java的引用传递),取到后从三级缓存移动到了二级缓存完全初始化之后将自己放入到一级缓存中
核心源码如下:
//维护着所有创建完成的Bean bean name-->bean instance (一级缓存)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//维护着创建中Bean的ObjectFactory bean name-->ObjectFactory (三级缓存)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//维护着所有半成品的Bean (二级缓存)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从singletonObjects获取已创建的Bean
Object singletonObject = this.singletonObjects.get(beanName);
//如果没有已创建的Bean,但是该Bean正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从earlySingletonObjects获取已经实例化的Bean
singletonObject = this.earlySingletonObjects.get(beanName);
//如果没有实例化的Bean,但是参数allowEarlyReference为true
if (singletonObject == null && allowEarlyReference) {
//从singletonFactories获取ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//使用ObjectFactory获取Bean实例
singletonObject = singletonFactory.getObject();
//将Bean实例放入earlySingletonObjects中,并从singletonFactories中移除
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
以A、B循环依赖注入为例,流程图如下:
addSingletonFactory()
方法缓存,然后执行依赖注入BgetSingleton()
方法得到这个A的提前引用(拿到最开始缓存的objectFactory,通过它取得对象引用),这样B的依赖注入就完成了加入singletonFactories
三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决
6)、如何关闭循环依赖
//创建ApplicationContext容器
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
//设置配置文件路径
applicationContext.setConfigLocation("classpath:circular-dependence.xml");
//关闭循环依赖
applicationContext.setAllowCircularReferences(false);
//启动Spring应用上下文
applicationContext.refresh();
A a = (A) applicationContext.getBean("a");
System.out.println(a);
Spring AOP采用动态代理机制(JDK动态代理)和字节码生成技术(CGLIB动态代理)实现,二者都是在运行期间为目标对象生成一个代理对象,而将横切逻辑织入到这个代理对象中,系统最终使用的是织入了横切逻辑的代理对象,而不是真正的目标对象
Spring AOP属于运行时增强,而AspectJ是编译时增强。Spring AOP基于代理,而AspectJ基于字节码操作
传播行为 | 含义 | 备注 |
---|---|---|
REQUIRED | 当方法调用时,如果不存在当前事务,那么就创建事务;如果之前当方法已经存在事务了,那么就沿用之前的事务 | Spring默认的传播行为 |
SUPPORTS | 当方法调用时,如果不存在当前事务,那么不启用事务;如果存在当前事务,那么就沿用当前事务 | |
MANDATORY | 方法必须在事务内运行 | 如果不存在当前事务,那么就抛出异常 |
REQUIRES_NEW | 无论是否存在当前事务,方法都会在新的事务中运行 | 事务管理器会打开新的事务运行该方法 |
NOT_SUPPORTED | 不支持事务,如果不存在当前事务也不会创建事务;如果存在当前事务,则挂起它,直至该方法结束后才恢复当前事务 | |
NEVER | 不支持事务,只有在没有事务的环境中才能运行它 | 如果方法存在当前事务,则抛出异常 |
NESTED | 嵌套事务,也就是调用方法如果抛出异常只回滚自己内部执行的SQL,而不回滚主方法的SQL |
参考:
Spring Framework中文文档:https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/core.html#beans
《Spring揭秘》
《Spring官网读书笔记》:https://blog.csdn.net/qq_41907991/category_9601507.html
《@Autowired注解的实现原理》:https://juejin.im/post/5d9487b55188252dfc5727da
《简单说说Spring的循环依赖》:https://juejin.im/post/5da727046fb9a04e2e4b1ca6
《互联网公司 Spring 面试大全(100 题)》:https://gitchat.csdn.net/activity/5d3c724bdf8cc803e66f1e18#61springbeans
《Spring常见问题总结(补充版)》:https://mp.weixin.qq.com/s/wcK2qsZxKDJTLIGqEIyaNg