Spring IOC和AOP
IOC部分:
1.Spring是什么?
Spring是一个生态,可以构建java应用所需要的一切基础设施。通常spring指的是spring frameWork.
一般的生态来说:
-
1.Spring FrameWork
-
2.SpringBoot
增加了自动配置
总结一下,其实就是 Spring Boot 在启动的时候,按照约定去读取 Spring Boot Starter 的配置信息,再根据配置信息对资源进行初始化,并注入到 Spring 容器中。这样 Spring Boot 启动完毕后,就已经准备好了一切资源,使用过程中直接注入对应 Bean 资源即可 -
3.SpringMVC
-
4.SpringCloud
分布式的springboot,适用于分布式
而spring 是一个轻量级开源框架:
IOC:控制翻转
AOP:面向切面编程
2 .IOC控制反转
本意: 对象的创建由我们自己new转到了spring ioc容器中,由spring ioc容器统一管理、
这样的好处: 降低对象间的耦合度
底层分析: xml配置文件、反射、简单工厂模式
我们通过读取xml配置文件(bean id+class),通过读取类的全路径,来进行反射创建对象,然后这个过程是由spring ioc完成的,我们只需要调用它提供的方法即可获得对象,这是简单工厂模式。
3.IOC的两种实现
1)BeanFactory接口
这个接口是基本实现,一般不提供开发人员使用,并且加载配置文件的时候是懒加载,不会创建对象。
2)ApplicationContext接口(其中实现的是BeanFactory接口)
这个接口是提供给开发人员使用的,有相对多的功能,加载配置文件的就会创建对象,所以相对式慢启动、快响应。
4.Bean的管理
1)创建对象
2)为对象设置属性
一般分为基于xml的配置文件和基于注解方式的实现:
xml文件:
创建对象:在xml文件配置bean
注入属性(DI):构造注入/设置注入(set),可以注入简单属性的值,也可以注入其他类的对象,包括注入外部bean、注入内部bean、
基于注解:
创建对象:在xml文件配置component-scan,然后再要创建对象的类上加入注解:@component、@service、@Reposity、@Controller
注入属性(DI):在属性上加入注解:@Autowire、@Vlaue、@Qualifier、@Resource
5:DI和IOC
可以看到IOC式控制翻转,主要是创建对象的思想,而真正的实现是由反射+简单工厂,然后通过DI技术实现对象的属性赋值
6.scope
一般是单例、可以设置多例、还有不常用session、request,一次请求创建一个bean,一个会话创建一个bean
7.spring的单例安全
单例:一般如果涉及到无状态的bean(没有属性),那么肯定用单例,并且安全
但是如果有状态的bean,单例则不安全了,我们一般用多例模式;当然还可以在单例模式下设置属性ThreadLocal来保证每个线程有自己的属性。
8.spring bean的常见生命周期
简单来说:
创建对象---->注入属性---->后置处理器的Before方法------>初始化方法-------->后置处理器的After方法------>获得对象
销毁对象------>调用destory方法(写了才有用)
为了更好理解,可以重构成实例化、属性注入、初始化、销毁四个主要部分,其余部分相当于使用AOP技术,如果实现了相关接口,才会有这些过程。
- 1.BeanFactoryPostProcessor的bean定义
- BeanFactoryPostProcessor接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。
说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性 - 2.InstantiationAwareBeanPostProcessor的bean定义
- postProcessBeforeInstantiation方法
- 3.实例化
- 4.InstantiationAwareBeanPostProcessor的bean定义
- postProcessAfterInstantiation方法
- 5.注入属性
- 6.Aware接口
【BeanNameAware接口】调用BeanNameAware.setBeanName()
【BeanFactoryAware】调用BeanFactoryAware.setBeanFactory()
【ApplicationContextAware】调用ApplicationContextAware.setApplicationContext() - 7.BeanPostProcessor的bean定义
- postProcessBeforeInitialization方法
- 8.InitializingBean的接口
- InitializingBean.afterPropertiesSet()方法
- 9.初始化init
- 10.BeanPostProcessor的bean定义
- postProcessAfterInitialization方法
- 11.DisposableBean接口
- destroy()方法
- 12.自定义init_destory()方法
9.Spring 怎么解决循环依赖问题?
- 三级缓存
- singletonObjects 一级缓存
- earlySingletonObjects 二级缓存
- singletonFactories 三级缓存
情景一(没有循环依赖)----一级缓存
情景二(有循环依赖,没有Aop) -----二级缓存
最后把半成品池(二级缓存)的对象销毁;
注:无法解决Aop代理对象
情景三(有循环依赖,有Aop)----三级缓存
步骤:(待)
https://blog.csdn.net/lkforce/article/details/97183065
https://blog.csdn.net/m0_43448868/article/details/113578628
https://www.bilibili.com/video/BV1ET4y1N7Sp?p=1
参考链接:
https://www.nowcoder.com/discuss/747711
https://blog.csdn.net/qq_36714200/article/details/111240510
AOP部分
1.AOP
面向切面编程,
主要本质: 对业务逻辑的各个部分进行分离,从而业务逻辑和一些其他非业务逻辑:事务、日志等分隔开,同理降低耦合度,并且代码的复用能力。
2.静态代理和动态代理
静态代理:
对一个类,我们利用其对象来调用其方法,但是我们生成一个代理类,这个代理类作为其访问的接口,并且我们可以在其对象方法前后加上自己的新的逻辑功能,进行增强。— 编译时完成
动态代理:
不同于静态代理,我们在运行时进行动态代理类的生成,主要分为两种:
1)基于JDK
接口+实现类
主要是反射实现的,代理类Proxy,主要是三个参数(实现类的类加载器、实现类的接口、实现invocationhandler接口的对象(实现类对象)
2)基于CGLIB
没有接口,只有实现类,通过ASM开源包
对代理对象类的class文件加载进来,通过修改字节码生成子类处理。因此如果被代理类被final关键字所修饰,会失败。
内部是实现”MethodInterceptor“接口,而这个接口内部获得实现类的元对象,并把它设置为Enhance类的父类,所以这是继承的思想,在其字节码中的指定对象前后加入自己处理逻辑。
3)对比
cglib的创建效率低,调用效率高;而spring默认是jdk代理,但是如果没有实现接口,则强制使用CGLib来实现动态代理。
3.spring的常用设计模式
1)简单工厂模式—IOC
2)单例模式—bean
3)动态代理----AOP
4.AOP的实现
术语:
连接点:类中的方法(不用记)
切入点:这个才有用,真正被增强的方法
切面:将通知应用到切入点的过程,是一个动作
通知/增强:实际增强的逻辑部分,自己写的代码部分
- 类型:前置通知、后置通知、环绕通知、异常通知、最终通知
- @Before、@AfterReturning、@Around、@AfterThrouing、@After
注:就是定义好切入点、通知,然后利用切面来将通知加入到切入点上。
配置:可以通过切入点表达式@PointCut
代码实现:
-
引入依赖
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
-
1.xml配置实现
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--配置aop:需要导入aop的命名空间--> <aop:config> <!--配置切入点 --> <aop:pointcut id="point" expression="execution(* dao.*.*(..))"/> <!-- 配置通知点,需要log类实现相关的接口--> <aop:advisor advice-ref="log" pointcut-ref="point"/> </aop:config>
/* Before(方法执行前) :org.apringframework.aop.MethodBeforeAdvice AfterReturning(方法返回后) :org.springframework.aop.AfterReturningAdvice After-throwing(异常抛出后) :org.springframework.aop.ThrowsAdviceArround 环绕,即方法前后 :org.aopaliance.intercept.MethodInterceptor */ public class Log implements MethodBeforeAdvice, AfterReturningAdvice,MethodInterceptor { public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("BeforeAdvice方法执行前"); System.out.println(method.getName()+";"+o.getClass()); } public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("AfterAdvice方法执行前"); System.out.println(method.getName()+";"+o.getClass()); } public Object invoke(MethodInvocation methodInvocation) throws Throwable { System.out.println("Roundadvice方法执行前"); System.out.println(methodInvocation.getArguments()[0]);//可以获取目标方法的参数值 Object result=methodInvocation.proceed();//调用目标对象的方法 System.out.println("RoundAdvice方法执行完成了"); return result; } }
-
2.注解实现
-
xml配置
<!-- JDK(默认proxy-target-class="false") cglib(proxy-target-class="true")--> <aop:aspectj-autoproxy/>
//定义切面 //定义bean @Aspect @Component public class MyAspect { //配置切点,切点的这个方法不需要实现,只是为了给切面的方法作为锚点 @Pointcut("execution(* testExecution(..))") public void anyTestMethod() {} //**配置前置通知,使用在anyTestMethod上注册的切入点**很重要!!! @Before("ric.study.demo.aop.MyAspect .anyTestMethod()") public void doAccessCheck(JoinPoint joinPoint) { // ... 实现代码 } // returnVal 就是相应方法的返回值 // 注意可以通过这样去为你的aop方法获得更多的参数打印详细信息,只要是该注解提供的参数都是这样获取 @AfterReturning( pointcut="ric.study.demo.aop.MyAspect .anyTestMethod()", returning="returnVal") public void doAccessCheck(Object returnVal) { // ... 实现代码 } // 这种最灵活,既能做 @Before 的事情,也可以做 @AfterReturning 的事情 @Around("ric.study.demo.aop.MyAspect .anyTestMethod()") public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { // target 方法执行前... 实现代码 Object retVal = pjp.proceed(); // target 方法执行后... 实现代码 return retVal; } }
https://zhuanlan.zhihu.com/p/127792838
5.spring事务的配置
-
1.编程式事务管理
编程式事务管理是侵入性事务管理,使用TransactionTemplate或者直接使用PlatformTransactionManager,对于编程式事务管理,Spring推荐使用TransactionTemplate。 -
2.声明式事务管理
声明式事务管理建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。 -
3.比较
编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现,只需要在配置文件中做相关的事务规则声明或者通过注解的方式,便可以将事务规则应用到业务逻辑中。
显然声明式事务管理要优于编程式事务管理,这正是Spring倡导的非侵入式的编程方式。唯一不足的地方就是声明式事务管理的粒度是方法级别,而编程式事务管理是可以到代码块的,但是可以通过提取方法的方式完成声明式事务管理的配置(黑体不懂)
6.spring事务的传播?
事务的传播性一般用在事务嵌套的场景,比如一个事务方法里面调用了另外一个事务方法,那么两个方法是各自作为独立的方法提交还是内层的事务合并到外层的事务一起提交,这就是需要事务传播机制的配置来确定怎么样执行。
常用的事务传播机制如下:
- PROPAGATION_REQUIRED
Spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行 - PROPAGATION_REQUES_NEW
该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可 - PROPAGATION_SUPPORT
如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务 - PROPAGATION_NOT_SUPPORT
该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码 - PROPAGATION_NEVER
该传播机制不支持外层事务,即如果外层有事务就抛出异常 - PROPAGATION_MANDATORY
与NEVER相反,如果外层没有事务,则抛出异常 - PROPAGATION_NESTED
该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。
传播规则回答了这样一个问题:一个新的事务应该被启动还是被挂起,或者是一个方法是否应该在事务性上下文中运行
- 点赞
- 收藏
- 关注作者
评论(0)