将创建对象的方式交给Spring来管理,应用程序需要的时候直接向Spring拿,而不是自己采用new的方式创建
对象a 依赖了对象 b,当对象 a 需要使用 对象 b的时候必须自己去创建。但是当系统引入了 IOC 容器后, 对象a 和对象 b 之前就失去了直接的联系。这个时候,当对象 a 需要使用 对象 b的时候, 我们可以指定 IOC 容器去创建一个对象b注入到对象 a 中"。 对象 a 获得依赖对象 b 的过程,由主动行为变为了被动行为,控制权反转了,这就是控制反转名字的由来。
动态地向对象中注入它所需要的其他对象,原理是通过反射
注入的方式,setter方法、构造器注入、注解自动注入(@Autowired、@Resource、@Value)
@Aspect切面,切面类的注解,代表是一个切面类
@PointCut切入点,指定哪些注解(一般是自定义注解用@interface)会进入这个切面
JoinPoint,连接点,程序进入切面的点
@Before在方法执行前需要的切面操作
@After在方法执行完成后需要的切面操作
@Around两者都可以有,在方法调用前后完成自定义行为
解耦、提高代码的复用率、开发者只需要注重纵向业务
AspectJ AOP使用的代理,编译时会生成AOP代理类,合并到Java字节码中(相当于帮我们改代码了)
Spring AOP使用的代理,如果被代理的实现了接口,就会采用的是jdk,其他情况采用的是cglib
核心是Proxy类和InvocationHandler接口
步骤如下:
创建代理类,通过代理类调用目标方法
反射调用invoke方法,将代码整合到一起
cglib是一个优秀的代码生成类库,采用继承的方式,生成一个被代理对象的子类来作为代理
Spring AOP 基于代理(Proxying),而 AspectJ AOP基于字节码操作(Bytecode Manipulation)。
@EnableAspectJAutoProxy注解实际上就是向容器中注册了一个AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,这个类本身就是一个后置处理器,AOP代理就是由它在这一步完成的
执行AnnotationAwareAspectJAutoProxyCreator的postProcessBeforeInstantiation方法,实际上就是父类AbstractAutoProxyCreator的postProcessBeforeInstantiation被执行
注意:Instantiation是实例化;Initialization是初始化
实际上也是执行父类AbstractAutoProxyCreator中的方法
对需要进行代理的Bean完成AOP代理的创建
图片来源:https://blog.csdn.net/qq_41907991/article/details/107141101
@Controller、@Component、@Service、@Repository
@Autowired、@Resource、@Qualifier、@Value
@Autowired按照类型(ByType)注入,存在多个的时候用@Qualifier制定具体的名称
@Resource按照名称(ByName)注入
@Configuration、@Bean、@ComponentScan(扫描Bean)
@Aspect、@PointCut、@Before、@After、@Around
@EnableAync、@Async
@RequestMapping:映射请求url
@RequestParam:获取请求路径后面的参数值
@RequestBody:获取请求体上的参数值
@ResponseBody:接口返回以json的形式
@ControllerAdvice:定义一个异常类
@ExceptionHandler:用于全局处理控制器里的异常
DispatcherServlet、HandlerMapping、Handler、HandlerAdapter、视图解析器
// 忽略了无关代码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
// 1. 实例化阶段!
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 2. 属性赋值阶段!
populateBean(beanName, mbd, instanceWrapper);
// 3. 初始化阶段!
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
主要流程:实例化、属性赋值、初始化、销毁
通过构造器实例化,选择最佳构造方法
注意:实例化结束后对外暴露的是ObjectFactory(用于获取Bean的工厂类)而不是实例化对象本身,可以提供getObject() 来获取Bean实例。
使用setter方法对属性进行赋值操作
实现DisposableBean接口调用destroy方法
初始化Aware相关的Bean
实例化阶段前后
作用于初始化阶段的前后,初始化前调用postProcessBeforeInitialization,初始化之后调用postProcessAfterInitialization
BeanPostProcessor调用postProcessAfterInitialization方法创建的
两者都是对Spring创建Bean提供的扩展点
BeanFactoryPostProcessor早点,只有1方法,在Bean实例化之前执行的
BeanPostProcessor晚点,有2个方法,分别是在Bean初始化前后执行的
所有的Aware方法都是在初始化阶段之前调用的
帮助我们拿到Spring容器的xxx资源
参考:https://www.jianshu.com/p/1dec08d290c1.
用setter方法注入(非构造方法注入),且对于单例模式下的Bean
注意:如果是构造器注入引起的循环依赖,直接启动不了,无解
Bean的生命周期(实例化和属性赋值分开)、ObjectFactory、三级缓存
ClassA引用ClassB,ClassB中又引用了ClassA。
A的实例化,Spring选择合适的构造器实例化A,并把A的ObjectFactory放入到三级缓存中
A的属性赋值,赋值的过程中,发现成员变量B为被实例化,接着会去执行B的生命周期
B的实例化,Spring选择合适的构造器实例化B,并将B的ObjectFactory放入到三级缓存中
B的属性赋值,赋值的过程中,发现成员变量A能够在三级缓存中找到(半成品),B属性赋值成功,删除二级、三级缓存中的Bean,保存到一级缓存中。
回到A的属性赋值,A属性赋值成功(完成品),删除二级、三级缓存中的Bean,保存到一级缓存中
从三级缓存中取出Bean对应的ObjectFactory实例,调用其getObject方法,来获取早期曝光Bean,最终会调用getEarlyBeanReference方法
拿到半成品的bean实例(属性未填充),从三级缓存移除,放到二级缓存earlySingletonObjects中
注意:此时B注入的是一个半成品的实例A对象,不过随着B初始化完成后,A会继续进行后续的初始化操作,最终B会注入的是一个完整的A实例,因为在内存中它们是同一个对象
2种情况:
好像只需要用到三级缓存就可以了,为什么要用到二级缓存?
getEarlyBeanReference方法返回的是代理对象,还是被CGLIB代理的,每次执行都会产生一个新的代理对象
这就会有问题了,因为A是单例的,每次执行singleFactory.getObject()方法又会产生新的代理对象,假设这里只有一级和三级缓存的话,我每次从三级缓存中拿到singleFactory对象(也可以认为是ObjectFactory),执行getObject()方法又会产生新的代理对象,这是不行的,因为A是单例的,所有这里我们要借助二级缓存来解决这个问题,将执行了**singleFactory.getObject()**产生的对象放到二级缓存中去,后面去二级缓存中拿,没必要再执行一遍singletonFactory.getObject()方法再产生一个新的代理对象,保证始终只有一个代理对象
在Bean被AOP代理的情况下,保证始终只有一个代理对象
如果没有AOP的话确实可以两级缓存就可以解决循环依赖的问题,如果加上AOP,两级缓存是无法解决的,不可能每次执行singleFactory.getObject()方法都给我产生一个新的代理对象,所以需要借助另外一个缓存来保存产生的代理对象
参考一下优秀的文章:Spring 为何需要三级缓存解决循环依赖,而不是二级缓存
存在ConcurrentHashMap中,用来存放已经初始化完成的Bean
存在HashMap中,存放半成品的Bean,一般处于循环引用的Bean才会暂时保存在这个缓存里
存在HashMap中,存放ObjectFactory实例(用来获取Bean的工厂类)、在IoC容器中,所有刚被创建出来的ObjectFactory,默认都会保存到该缓存中。
spring会提前将已经实例化的bean通过ObjectFactory半成品暴露出去
半成品是指:bean对象已经实例化,但是未进行属性填充,是一个不完整的bean实例对象
设定方式:xml用scope指定、注解@Scope(value = “singleton”)指定
小tips:singleton作用域下才会走spring的生命周期流程、prototype用到的时候才走
不是,但是像Controller、Service这些大多数都是无状态的,不存在除了查询以外的操作,所以很安全;对于有状态的Bean 可以设置Bean的作用域为prototype,对于每个线程都有各自的Bean,绝对安全
spring默认创建的bean就是单例的
spring通过ConcurrentHashMap实现单例注册表的特殊方式实现单例模式
通过BeanFactory 或 ApplicationContext 创建 bean 对象。
BeanFactory 延迟注入,用到的时候才会实例化Bean,优点启动块。(以前内存还不够用的时候)
白话文:懒汉模式的思想
ApplicationContext 启动时就会实例化所以Bean,扩展了BeanFactory,有额外功能(用的多)
白话文:饿汉模式的思想
Spring AOP的原理就是采用动态代理。例如AopProxy、CglibAopProxy、JDKDynamicProxy
一般实现:使用继承抽象父类并@Override其父类的abstract方法
jdbcTemplate使用Callback 模式与模板方法模式配合,既达到了代码复用的效果,同时增加了灵活性
Spring AOP 的Advice通知用到了AdvisorAdapter,搭配拦截器使用
SpringMvc中 DispatcherServlet根据请求信息调用HandlerMapper,解析出来的Handler,交给HandlerAdapter(适配器),适配对应的Controller类
例如:BeanPostProcessor (具体哪里体现策略模式?todo)
事务内的操作,要么全部执行,要么全部回滚。
强调数据库在逻辑上的一致性状态,依赖于原子性。
两个事务之间互不影响
事务被提交之后,事务的一系列操作的结果是需要落库的
@Transactional(isolation = Isolation.DEFAULT)
@Transactional(propagation = Propagation.REQUIRE)
对下面7种事务的方法就行总结
采用注解@Transactional实现,原理是AOP,Spring启动的时候会扫描这个注解相关的类,并生成代理类,主要功能如下:
在Before时,根据propagation属性确定事务的传播行为
在After时,切面需要确定事务被提交,回滚或者继续运行,真正的数据库层的事务提交和回滚是通过bin log或者redo log实现的
对代码有侵入性,不建议