SpringAOP实现原理
Spring的切面编程,从织入方式上来看,存在三种织入方式:编译期织入、类加载期织入和运行期织入.aspectJ有两种织入方式:CTW(Compile Time Weaving)编译时织入和LTW(Load Time Weaving)加载时织入,Spring Aop是在运行期通过代理技术动态扩展被增强类(JDK动态代理和cglib动态代理)
通过动态代理在方法运行过程中动态的添加功能,可以更好的降低模块的耦合度、易扩展,在 Spring IOC 容器中在 getBean 时返回的是代理类的实例,是Spring 采用 JDK Proxy 或 CGLIB 动态生成的
开启Aop功能的三种方式:xml配置< aop-config>aop功能,< aspectj-autoproxy>aop注解方式,SpringBoot通过@EnableAspectJAutoProxy注解开启aop,其实本质都是依赖aop包提供的AOP解析器进行处理
Aop解析器
在loadBeanDefinition中parseCustomElement解析非默认标签和自定义namespace会从资源路径下META-INF/spring.handlers找到对应的schema,在aop包中会默认加载AopNamespaceHandler
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
根据xml标签注册了以下几个解析器,最后调用解析器parse方法解析配置项
public void init() {
//xml配置pointcut,advisor元素
this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
ConfigBeanDefinitionParser
对应的是xml配置中aop-config的配置解析器
<!-- 定义增强器的内容(方法) -->
<bean id="transaction" class="com.test.springtest.aop.TransactionDemo"/>
<!--配置AOP proxy-target-class采用代理模式,默认为false也就是JDK代理通过接口进行代理,设置为true时使用cglib代理通过继承目标类实现代理-->
<!--expose-proxy暴露代理用于AopContext.currentProxy()获取当前代理,用于例如在A对象x方法中调用另外一个类的y方法时,y方法不会被切面增强,这时可以配置expose-proxy为true并将this.y()改为获取代理的实例去((A)AopContext.currentProxy()).y(),即可让y方法被切面增强-->
<aop:config proxy-target-class="true" expose-proxy="true">
<!-- 全局的pointcut -->
<aop:pointcut id="mycut" expression="execution(* com.pingan.mytest.test..*.*(..))"/>
<aop:aspect ref="transaction">
<!--切入点: 匹配service及其子包下的所有类,类中所有方法,不论参数-->
<aop:pointcut id="demoPointcut" expression="execution(* com.pingan.test.springtest.aop.service..*.*(..))"/>
<!--目标方法执行前会先执行transaction中的testBefore-->
<aop:before method="testBefore" pointcut-ref="demoPointcut"/>
<!--方法执行后-->
<aop:after method="testAfter" pointcut-ref="demoPointcut"/>
<!--方法执行环绕-->
<aop:around method="testAround" pointcut-ref="demoPointcut"/>
<!--后置返回-->
<aop:after-returning method="testAfterAround" pointcut-ref="demoPointcut"/>
<!--异常-->
<aop:after-throwing method="testEx" pointcut-ref="demoPointcut" throwing="ex"/>
</aop:aspect>
<!--和aspect功能一样,advise-ref必须依赖一个Advice接口的实现-->
<aop:advisor advice-ref="testAdvice" pointcut-ref="mycut"/>
</aop:config>
对应的advise增强方法
//自定义一个切面
public class TransactionDemo {
//在被切入方法执行前触发,顺序为1
public void testBefore(){
System.out.println("方法执行前");
}
//最终触发
public void testAfter(){
System.out.println("方法执行完");
}
//环绕增强:前置+目标方法执行+后置通知
//ProceedingJoinPoint继承JoinPoint
public void around(ProceedingJoinPoint point) throws Throwable {
//如果有前置增强,则顺序为2
System.out.println("方法环绕前");
//proceed方法用于启动目标方法执行,顺序为3
point.proceed();
//顺序5
System.out.println("方法环绕后");
}
//后置返回增强:当目标方法执行返回之后,顺序为4
public void testafterAround(){
System.out.println("方法返回值通知");
}
//抛出异常后执行方法,before-环绕前-目标方法-异常通知-after
public void testThrowAround(Exception ex){
System.out.println(ex.getMessage());
}
}
element节点就是aop-config
public BeanDefinition parse(Element element, ParserContext parserContext) {
//首先会注册一个AspectJAwareAdvisorAutoProxyCreator,处理<aop:config>节点,解析proxy-target-class和expose-proxy的属性值
//AspectJAwareAdvisorAutoProxyCreator也AbstractAutoProxyCreator的实现
this.configureAutoProxyCreator(parserContext, element);
//获取<aop:config>节点的子元素
List<Element> childElts = DomUtils.getChildElements(element);
Iterator var5 = childElts.iterator();
while(var5.hasNext()) {
Element elt = (Element)var5.next();
//包括全局的pointcut(aspect子元素也有pointcut),aspect和advisor
String localName = parserContext.getDelegate().getLocalName(elt);
if ("pointcut".equals(localName)) {
this.parsePointcut(elt, parserContext);
} else if ("advisor".equals(localName)) {
this.parseAdvisor(elt, parserContext);
} else if ("aspect".equals(localName)) {
this.parseAspect(elt, parserContext);
}
}...
}
AspectJAutoProxyBeanDefinitionParser
在xml配置中开启注解模式
<!--开启切面注解解析器-->
//对应<aop:config proxy-target-class="true" expose-proxy="true">
<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>
//标签aspectj-autoproxy对应注册的解析器就是AspectJAutoProxyBeanDefinitionParser
//主要作用是注册一个AnnotationAwareAspectJAutoProxyCreator
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
//@Aspect对应xml配置中开启一个切面:<aop:aspect ref="transaction">
@Aspect
@Component("transaction")
public class TransactionDemo {
//配置切入点Pointcut:<aop:pointcut id="demoPointcut" expression="execution(xx)"/>
@Pointcut("execution(* com.test.springtest.aop.service..*.*(..))")
public void pointcut(){}
//前置增强,引入切入点方法 <aop:before method="before" pointcut-ref="pointcut"/>
@Before(value = "pointcut()")
public void before(){
System.out.println("方法执行前");
}
@After(value = "pointcut()")
public void after(){
System.out.println("方法执行完");
}
//ProceedingJoinPoint封装方法中参数
@Around(value = "pointcut()")
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("方法环绕前");
point.proceed();
System.out.println("方法环绕后");
}
@AfterReturning(value = "pointcut()")
public void afterAround(){
System.out.println("方法返回值通知");
}
//<aop:after-throwing method="throwAround" pointcut-ref="pointcut" throwing="ex"/>
@AfterThrowing(value = "pointcut()",throwing = "ex")
public void throwAround(Exception ex){
System.out.println(ex.getMessage());
}
}
@EnableAspectJAutoProxy注解开启aop功能本质上也是注册了AnnotationAwareAspectJAutoProxyCreator
//@import等同于给AspectJAutoProxyRegistrar加了一个@Component注解
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
//对应<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
//实现了ImportBeanDefinitionRegistrar
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
AspectJAutoProxyRegistrar() {
}
//在实例化bean时执行这个方法
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//注册AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
//获取@EnableAspectJAutoProxy注解
AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
...
}
}
然后继续分析一下AnnotationAwareAspectJAutoProxyCreator
//继承的抽象类实现了SmartInstantiationAwareBeanPostProcessor和BeanFactoryAware两个接口
//SmartInstantiationAwareBeanPostProcessor是个InstantiationAwareBeanPostProcessor,实例化bean时会调用其postProcessAfterInitialization方法从而改变包装wrapBean的bean实现增强
//BeanFactoryAware则了解到封装了BeanFactory
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {}
ConfigBeanDefinitionParser中注册了AspectJAwareAdvisorAutoProxyCreator也是AbstractAutoProxyCreator的实现,所以aop的处理都在实例化bean的时候
Advisor增强器
对于advise和advisor其实本质上都类似interceptor,当访问了某个方式时进行拦截并对这个方法进行增强;切点pointcut表示在什么位置进行增强,而Aspect则可以理解为一个拦截器链
切入点Pointcut
AspectJ切入点,标注匹配的方法和类,表达式第一个*表示匹配所有方法的返回值,两个.表示0或多个子包,service包下包括子包的所有的类,及其所有的方法,匹配所有参数,(…)中表示任意参数
//主要是将解析的配置项封装为一个AspectJExpressionPointcut
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
//获取标签的两个属性值
String id = pointcutElement.getAttribute("id");
String expression = pointcutElement.getAttribute("expression");
/*创建AspectJExpressionPointcut
beanDefinition.setBeanClass(AspectJExpressionPointcut.class);
beanDefinition.setScope("prototype");
beanDefinition.setSynthetic(true);
beanDefinition.getPropertyValues().add("expression", expression);
*/
AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
String pointcutBeanName = id;
//beanDefinitionMap.put(beanName, beanDefinition);beanName就是id
parserContext.getRegistry().registerBeanDefinition(id, pointcutDefinition);
return pointcutDefinition;
}
切入点匹配方式:
**execution:**使用"execution(方法表达式)"匹配方法执行;
主要两种方式:
1.根据全限定名去匹配切点的目标方法
2.根据注解去匹配目标方法
<!--切入点: 匹配service及其子包下的所有类,类中所有方法,不论参数-->
<aop:pointcut id="demoPointcut" expression="execution(* com.test.aop.service..*.*(..))"/>
<!--切入点:任何持有@com.pingan.test.springtest.aop.AnnoAspect注解的方法-->
<aop:pointcut id="demoPointcut" expression="execution(@com.test.aop.AnnoAspect * *(..))"/>
注解示例
@Aspect
@Component
public class AspectTest {
//方法的入参用于value值,returnValue表示方法返回值
@AfterReturning(value = "@annotation(testAnno)",returning = "returnValue")
public String processTest(TestAnno testAnno,Object returnValue) {
String result = (String) returnValue;
System.out.println(result);
return result;
}
}
**within:*使用"within(类型表达式)“或者”@within(注解类型)"匹配持有指定注解类型内的方法,注意没有
<!--注解要贴在实现类上面,类所有的方法都会被织入-->
<aop:pointcut id="demoPointcut" expression="within(@com.test.aop.AnnoAspect *)"/>
<!--@within和上面是一样的作用,区别在于@的位置和最后的*在@within方式不需要-->
<aop:pointcut id="demoPointcut" expression="@within(com.test.aop.AnnoAspect)"/>
**this:**使用"this(类型全限定名)"匹配类型全限定名,不支持通配符,this引用的是当前对象,不是代理对象
**target:**使用"target(类型全限定名)"匹配类型全限定名,不支持通配符,target引用的代理对象
目标对象(Target Object) :被一个或者多个切面所通知的对象。例如,AServcieImpl和BServiceImpl,当然在实际运行时,Spring AOP采用代理实现,实际AOP操作的是TargetObject的代理对象
<aop:pointcut id="demoPointcut" expression="this(com.test.aop.service.SuperService)"/>
**args:**使用"args(参数类型列表)"匹配当前执行的方法传入的参数为指定类型的执行方法;
<!--切入点:匹配传入的参数类型为String的方法-->
<aop:pointcut id="demoPointcut" expression="args(java.lang.String)"/>
public void args(String args){
System.out.println("测试args语法切入点");
}
增强器链Aspect
可包含多个增强器
<!-- 增强(Advice):通知,在方法执行的什么时机(方法前/方法后/方法前后)做什么(增强的功能)-->
<aop:before method="before" pointcut-ref="demoPointcut"/>
<aop:after method="after" pointcut-ref="demoPointcut"/>
<!--aspect包括pointcut和advise-->
<aop:aspect ref="transaction">
<!--pointcut-->
<aop:pointcut id="demoPointcut" expression=""/>
<!--advice-->
<aop:before method="" pointcut-ref="demoPointcut"/>
</aop:aspect>
aspect标签包含的pointcut标签和advise标签
private void parseAspect(Element aspectElement, ParserContext parserContext) {
//解析aspect标签的id和ref属性,ref引用的实例就是封装通知的方法,比如testAfter()
String aspectId = aspectElement.getAttribute("id");
String aspectName = aspectElement.getAttribute("ref");
...
//获取所有的子节点
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
for(int i = 0; i < nodeList.getLength(); ++i) {
Node node = nodeList.item(i);
//各种advise通知标签:before,after,around等
if(this.isAdviceNode(node, parserContext)) {
if(!adviceFoundAlready) {
adviceFoundAlready = true;
//封装为RuntimeBeanReference:主要的属性就是beanName表示对bean的引用
//封装的beanName是ref引用的bean
beanReferences.add(new RuntimeBeanReference(aspectName));
}
//解析advise节点并封装为AspectJPointcutAdvisor的bean
AbstractBeanDefinition advisorDefinition = this.parseAdvice(aspectName, i, aspectElement, (Element)node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
//处理pointcut子节点
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, "pointcut");
Iterator var21 = pointcuts.iterator();
while(var21.hasNext()) {
Element pointcutElement = (Element)var21.next();
this.parsePointcut(pointcutElement, parserContext);
}
}
解析advise增强器,主要包含method织入物和pointcut-ref/pointcut切点
private AbstractBeanDefinition parseAdvice(String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext, List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
//从MethodLocatingFactoryBean通过getObject获取的是method实例
//public Method getObject() throws Exception {return this.method;}
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
//targetBeanName表示原始的bean,也就是ref标签引用的bean
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
//method属性值引用的是bean的方法名methodName
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
methodDefinition.setSynthetic(true);
RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
//createAdviceDefinition主要是返回advise封装的bean和解析pointcut
/* 根据不同的advise封装为对应的bean
"before" return AspectJMethodBeforeAdvice;
"after" return AspectJAfterAdvice;
"after-returning" return AspectJAfterReturningAdvice;
"after-throwing" return AspectJAfterThrowingAdvice;
"around" return AspectJAroundAdvice;
*/
//beanDefinitions.add(pointcut);将pointcut解析封装的bean添加到beanDefinitions
//将methodDefinition作为bean的构造器参数封装
AbstractBeanDefinition adviceDef = this.createAdviceDefinition(adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef, beanDefinitions, beanReferences);
//继续将AdviceDefinition封装到AspectJPointcutAdvisor
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
//AdviceDefinition作为AspectJPointcutAdvisor构造器的参数封装
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
if(aspectElement.hasAttribute("order")) {
advisorDefinition.getPropertyValues().add("order", aspectElement.getAttribute("order"));
}
//注册advisorDefinition
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
实例化Advisor
advisor和aspect区别在于,一个aspect对应多个advise,而每个advisor只处理一个advise
//advisor标签所有属性
<aop:advisor advice-ref="" pointcut="" pointcut-ref="" id="" order=""/>
//一个advisor只能处理一个advise
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.XXX..*.*Service.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.XXX..*.*Rest.*(..))" />
注册一个DefaultBeanFactoryPointcutAdvisor
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
// public DefaultBeanFactoryPointcutAdvisor() {this.pointcut = Pointcut.TRUE;}
// 表示advisor依赖pointcut
//解析的标签属性添加在PropertyValues中:advice-ref,order
AbstractBeanDefinition advisorDef = this.createAdvisorBeanDefinition(advisorElement, parserContext);
//获取id标签,和上面一样可以定义DefaultBeanFactoryPointcutAdvisor实例的beanName
String id = advisorElement.getAttribute("id");
String advisorBeanName = id;
parserContext.getRegistry().registerBeanDefinition(id, advisorDef);
//解析pointcut和pointcut-ref属性并返回有效的pointcut添加到PropertyValues属性中
Object pointcut = this.parsePointcutProperty(advisorElement, parserContext);
advisorDef.getPropertyValues().add("pointcut", pointcut);
}
实例化的工作在doCreateBean进行到initializeBean即将完成初始化时调用所有后置处理器,包括AbstractAutoProxyCreator的applyBeanPostProcessorsAfterInitialization方法对aop的实例进行处理
public Object postProcessAfterInitialization(Object bean, String beanName) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
//如果被增强则将返回代理实例
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// Create proxy if we have advice.
//获取所有的advisor增强器(拦截器)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
//通过动态代理返回代理实例
if (specificInterceptors != null) {
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
//否则返回原bean
return bean;
}
getAdvicesAndAdvisorsForBean方法获取用于实现aop的配置项,xml配置在解析阶段就将配置项封装为各个类型的beanDefinition,而注解模式只是注册了AspectJAwareAdvisorAutoProxyCreator,并没有对注解配置项进行解析
//getAdvicesAndAdvisorsForBean主要获取合格的advisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//获取候选的advisor,也就是aspect解析之后的advisor实例
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//开启aop之后每个bean初始化都会匹配适合自己的advisor,简单理解就是是否匹配pointCut的advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
//AnnotationAwareAspectJAutoProxyCreator是注解配置项的代理生成器
protected List<Advisor> findCandidateAdvisors() {
//获取xml配置项的advisor并进行实例化为Advisor:beanFactory.getBean(name, Advisor.class);
List<Advisor> advisors = this.advisorRetrievalHelper.findAdvisorBeans();
//将注解配置项bean实例化并添加到advisors
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}
主要了解一下aspect注解项解析并实例化为Advisor
public List<Advisor> buildAspectJAdvisors() {
//遍历所有的bean
for (String beanName : beanNames) {
//类实例
Class<?> beanType = this.beanFactory.getType(beanName);
//类实例是否包含@Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
//AspectInstanceFactory切面实例工厂
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//AspectJAdvisorFactory advisorFactory
//初始化Advisor实例
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
advisors.addAll(classAdvisors);
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
//获取advise注解的方法,比如@After等,除了@PointCut之外
/*Advice类型
1.前置通知(Before advice):在连接点(JoinPoint)之前执行,但这个通知不能阻止连接点前的执行
2.后置通知(After advice):当某连接点退出的时候执行的通知,抛出异常时,returnAfter方法仍然执行。
3.返回后通知(After return advice):在某连接点正常完成后执行的通知,不包括抛出异常的情况。
4.环绕通知(Around advice):环绕连接点增强,ProceedingJoinPoint的proceed()用于目标方法执行
5.抛出异常后通知(After throwing advice):在方法抛出异常退出时执行,在配置时需要添加方法异常参数
<aop:after-throwing method="throwAround" pointcut-ref="demoPointcut" throwing="ex"/>
*/
for (Method method : getAdvisorMethods(aspectClass)) {
//解析advise注解的value值(表示切点),并将切点AspectJExpressionPointcut封装到advise中,和xml解析一样,再将advice封装到advisor中
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
每个bean初始化时都需要访问postProcessAfterInitialization方法,首先会判断是否是Aspect类(有@Aspect注解),如果是Aspect类则不是aspect类则返回原始的bean,再通过findAdvisorsThatCanApply判断当前bean是否匹配pointcut从而进行拦截增强
动态代理
被aop拦截的bean则开始创建代理类进行增强
//首先是createAopProxy()创建一个aopProxy
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
//默认使用jdk动态代理
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//如果proxyTargetClass设置为true
if (config.isProxyTargetClass()) {
Class<?> targetClass = config.getTargetClass();
//被代理的类是个接口还是使用jdk动态代理
if (targetClass.isInterface()) {
return new JdkDynamicAopProxy(config);
}
//否则使用的是cglib代理
return new ObjenesisCglibAopProxy(config);
}
return new JdkDynamicAopProxy(config);
}
JDK动态代理
代理的对象必须要实现接口,实际上也可以看作是代理类动态的实现了被代理对象的接口,JDK的Proxy类提供了一组静态方法来为一组接口动态地生成代理类及其对象:
//Proxy.newProxyInstance(类加载器,被代理的接口,代理处理器)
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder);
//实现InvocationHandler接口,创建增强代码的处理器
public Object invoke(Object proxy, Method method, Object[] args)
类是单继承的,所以jdk动态代理在继承proxy之后无法再继承一个实现类,所以只能通过实现接口的方式
//代理类继承Proxy代理类,实现接口的实现类代理
public class $ServerProxy extends Proxy implements IServer {
//实现InvocationHandler接口的invoke方法
protected $ServerProxy(InvocationHandler h) {
super(h);
}
//动态重写接口的方法
@Override
public void test() throws Throwable {
//获取方法对象
Method test = IServer.class.getMethod("test");
//调用代理处理器,真正的被代理的实现类在处理器中处理
h.invoke(this, test, null);
}
//依次类推重写其他接口的方法和Object对象的方法
}
动态代理的接口为IServer
//被代理的实现类,内部类调用局部变量时需要final标识
final Class<ServerImpl> serverClass = ServerImpl.class;
//interfaces:被代理的接口,hanlder:代理执行处理器,返回proxyInstance动态生成的代理对象
Object proxyInstance = Proxy.newProxyInstance(serverClass.getClassLoader(), serverClass.getInterfaces()
//实现InvocationHandler接口,在处理器中实现增强操作
, new InvocationHandler() {
// proxy:生成的代理对象,method:当前调用的真实方法对象,args:当前调用方法的实参
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("有没有被动态代理啊!");
Object invoke = method.invoke(serverClass.newInstance(), args);
//返回被代理的方法返回值
return invoke;
}
});
//虽然被代理的真实实现类为ServerImpl,但是底层的代理对象实现也是IServer接口
IServer server = (IServer) proxyInstance;
server.test();
//包括Object方法也被增强了
server.hashCode();
CGLIB动态代理
通过继承的方式实现动态代理,生成目标类的子类,并重写父类非final、非static、非private的修饰符的方法实现增强;动态代理的最小单位是类(所有类中的方法都会被处理)
//cglib是通过继承的方式实现动态代理
final Class<ServerImpl> serverClass = ServerImpl.class;
//创建代理类构造器对象
Enhancer enhancer = new Enhancer();
//设置要继承的父类
enhancer.setSuperclass(serverClass);
//添加增强处理器,InvocationHandler类是org.springframework.cglib.proxy.InvocationHandler
enhancer.setCallback(new InvocationHandler() {
// proxy:生成的代理对象,method :当前调用的真实方法对象,args:当前调用方法的实参
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("CGLIB动态代理!");
Object invoke = method.invoke(serverClass.newInstance(), args);
//返回被代理的方法返回值
return invoke;
}
});
//创建cglib动态代理对象
Object proxyInstance = enhancer.create();
//虽然被代理的真实实现类为ServerImpl,但是底层的代理对象实现也是IServer接口
IServer server = (IServer) proxyInstance;
server.test();
示例:打印post请求日志
@Pointcut("execution(public * cn.test.rest..*.*(..)) || execution(public * cn.test.controller..*.*(..))")
public void requestLog() {
}
@Around(value = "@annotation(postMapping)")
public Object requestLog(ProceedingJoinPoint joinPoint,PostMapping postMapping) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//获取切入的类
Class<?> restClass = joinPoint.getTarget().getClass();
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
//获取切入方法
Method method = signature.getMethod();
//获取切入方法的参数
Object[] args = joinPoint.getArgs();
//获取请求url
String url = request.getRequestURL().toString();
String requestParam = "";
if ("post".equalsIgnoreCase(request.getMethod())){
StringBuilder sb = new StringBuilder();
Arrays.stream(args).filter(object -> !(object instanceof HttpServletResponse) && !(object instanceof HttpServletRequest) && !(object instanceof MultipartFile) && !(object instanceof BeanPropertyBindingResult)).forEach((object) -> {
Object jsonObject = JSON.toJSON(object);
if (jsonObject != null) {
sb.append(JSON.toJSONString(jsonObject)).append("|");
}else {
sb.append(object).append("|");
}
});
requestParam = sb.append("flag").toString().replace("|flag", "");
}else {
requestParam = request.getQueryString();
}
log.info("requestUrl:{} requestParam is {}",url ,requestParam);
Object proceed = joinPoint.proceed();
log.info("response:{}",JSON.toJSONString(proceed));
return proceed;
}
Spring事务机制
Spring事务功能在spring-tx模块中,在SpringBoot项目中事务需要依赖mybatis-spring-boot-starter包从而引入spring-tx,开启Spring事务方式有三种:
第一种xml配置< tx:advice>增强器
<!--引入tx命名空间-->
xmlns:tx="http://www.springframework.org/schema/tx"
<!--配置事务管理器 使用JDBC,MyBatis的事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--依赖的也是数据源-->
<property name="dataSource" ref="dataSources"/>
</bean>
<!--通过AOP对方法做事务增强-->
<aop:config>
<aop:pointcut id="pc" expression="execution(* cn.mywork.service..*(..))"/>
<!--advisor只持有一个Pointcut和一个advice-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>
<!--配置事务管理的切面-->
<!--transaction-manager默认值为transactionManager,不注册transactionManager则默认为PlatformTransactionManager -->
<!--如果注册的beanName为transactionManager则使用注册的bean-->
<tx:advice id="myAdvice" transaction-manager="txManager">
<tx:attributes>
<!--name指匹配的方法名 read-only只读 isolation事务的隔离性 propagation传播性-->
<!--rollback-for/no-rollback-for 回滚/不回滚的异常类数组 timeout 超时时间-->
<tx:method name="*" read-only="true" isolation="READ_UNCOMMITTED" propagation="REQUIRED" rollback-for="Exception.class" timeout="-1" no-rollback-for=""/>
</tx:attributes>
</tx:advice>
第二种xml开启事务注解支持< tx:annotation-driven>
<!--transaction-manager事务管理器默认PlatformTransactionManager mode默认proxy-->
<!--MVC框架也有此类开启注解的节点 mvc:annotation-driven节点的解析器-->
<tx:annotation-driven proxy-target-class="" transaction-manager="" mode="aspectj"/>
@Transactional(
rollbackFor = {Exception.class,RuntimeException.class},
noRollbackFor = RuntimeException.class,
rollbackForClassName = "Exception")
第三种SpringBoot配置@EnableTransactionManagement
@SpringBootApplication
@EnableTransactionManagement(mode = AdviceMode.PROXY)
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
事务解析器TxAdviceBeanDefinitionParser
在xml文件解析阶段,获取所有META-INF/spring.handlers文件中对应的字节码全限定名对xml文件的标签初始化
//TxNamespaceHandler解析xml对应的3个节点
public void init() {
//本质上注册了一个Advice事务增强器TransactionInterceptor
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
//注解方式事务解析器
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
//分布式事务的应用 <tx:jta-transaction-manager/>
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
TxAdviceBeanDefinitionParser解析器对应< tx:advice>标签,继承了AbstractSingleBeanDefinitionParser,但是parse()解析节点的方法在AbstractSingleBeanDefinitionParser的父类AbstractBeanDefinitionParser中
//AbstractBeanDefinitionParser 主要是解析节点的id和name属性
public final BeanDefinition parse(Element element, ParserContext parserContext) {
//交给子类解析内部属性并构建为beanDefinition
AbstractBeanDefinition definition = parseInternal(element, parserContext);
//解析id属性
String id = resolveId(element, definition, parserContext);
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
//将id作为beanName添加到beanDefinition并注册到BeanFactory中
registerBeanDefinition(holder, parserContext.getRegistry());
return definition;
}
//AbstractSingleBeanDefinitionParser 这一步可以知道注册的是一个TransactionInterceptor
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
//构建一个空的Definition封装在builder中
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
//模板方法模式,通过子类TxAdviceBeanDefinitionParser获取一个TransactionInterceptor
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
//添加到上面那个未加工的beanDefinition中
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
//交给子类实现属性的解析
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
//TxAdviceBeanDefinitionParser 将attributes解析作为属性添加到TransactionInterceptor中
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
//将transaction-manager属性值,也就是管理器的beanName封装到RuntimeBeanReference
builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));
// 解析<tx:attributes>节点
List<Element> attributes = DomUtils.getChildElementsByTagName(element, "attributes");
if (attributes.size() == 1) {
Element attributeSourceElement = attributes.get(0);
//1.解析每个method节点,获取method方法的name
//2.构建一个attribute(TransactionDefinition)封装其他属性
//3.将name作为key,添加attribute到transactionAttributeMap
//4.构建一个NameMatchTransactionAttributeSource(包含一个nameMap缓存属性)的bean
//5.将transactionAttributeMap添加到Source的PropertyValues中(key:"nameMap")
RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
//将bean添加到builder.beanDefinition的PropertyValue中
builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
} else if(attributes.size() == 0) {
// 若没有attributes节点则注册一个注解事务属性
//也就是说只需要当<tx:advice id="myAdvice"/>存在时就可以使用@Transactional注解
builder.addPropertyValue("transactionAttributeSource",
new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
}
}
事务增强器TransactionInterceptor
实现事务机制的主要接口包括:
1. TransactionDefinition:封装事务属性,比如传播行为,隔离级别和超时时间,是否为只读事务等
2. PlatformTransactionManager:根据TransactionDefinition提供的事务属性配置信息,创建事务管理器
3. TransactionStatus:封装了事务的具体运行状态,比如,是否是新开启事务,是否已经提交事务,设置当前事务为rollback-only等
因为TransactionInterceptor是一个Interceptor,从而也是一个Advice,所以在实现aop时作为切面的增强器;其实和普通的aop没有什么区别,在初始化Advisor之后对切点匹配的方法进行事务增强;和其他advise的配置一样,都是通过的MethodInterceptor的invoke方法实现增强
//引用的txAdvice通过TransactionInterceptor实现增强
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
//MethodBeforeAdviceInterceptor实现Before方法的增强
<aop:before method="testBefore" pointcut-ref="demoPointcut"/>
public Object invoke(final MethodInvocation invocation) throws Throwable {
//获取需要增强的目标类
Class<?> targetClass = (invocation.getThis() != ...;
//交给父类TransactionAspectSupport实现增强
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
继续深入invokeWithinTransaction()方法
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
//如果是注解则通过AnnotationTransactionAttributeSource获取,否则获取的是NameMatchTransactionAttributeSource
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
//获取TransactionManager属性,比如配置的DataSourceTransactionManager
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
//开启手动事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
//执行目标方法,如果异常则根据匹配rollback等配置确定是否执行事务回滚con.rollback();
Object retVal = null;
try {
retVal = invocation.proceedWithInvocation();
} catch (Throwable ex) {
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
}
propagation事务的传播性
//获取propagation事务的传播行为,开启事务
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
// 配置的timeout如果小于-1则报错
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
int propagation = definition.getPropagationBehavior();
//因为当前并没有开启事务,所以PROPAGATION_MANDATORY行为时会报异常
if (propagation == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException("");
} else if (propagation == TransactionDefinition.PROPAGATION_REQUIRED ||
propagation == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
propagation == TransactionDefinition.PROPAGATION_NESTED) {;
DefaultTransactionStatus status = newTransactionStatus(..);
//获取数据库连接connection,取消自动提交con.setAutoCommit(false)
doBegin(transaction, definition);
return status;
}
}
//示例开启一个事务
Connection conn = DriverManager.getConnection(...);
try{
con.setAutoCommit(false);
Statement stmt = con.createStatement();
con.commit();
}catch(Exception e){
con.rollback();
}
Spring提供了7种事务传播级别,默认的是REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void testTx(){
}
//事务级别定义全部以B方法有事务为例
ServiceA {
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
void methodB() {
}
}
PROPAGATION_REQUIRED:如果A有事务则B加入到A的事务中,在methodA和methodB内的任何地方出现异常都要回滚,如果A没有事务则B进行自己的事务
PROPAGATION_REQUIRES_NEW:新建事务,比如设置A的事务级别为PROPAGATION_REQUIRED,B的事务级别为PROPAGATION_REQUIRES_NEW,那么当执行到B的时候,A所在的事务就会挂起,B会起一个新的事务,等待B的事务完成以后,A才继续执行。因为B是新起一个事务,那么就是存在两个不同的事务。如果B已经提交,那么A失败回滚,B是不会回滚的。如果B失败回滚,且抛出的异常被A捕获,A事务仍然可以提交。
PROPAGATION_SUPPORTS:如果当前A没有事务,B就以非事务方式执行,若A有事务则B加入到事务中
PROPAGATION_NOT_SUPPORTED:如果A的事务级别是PROPAGATION_REQUIRED ,那么当执行到B时,A的事务挂起,而B以非事务的状态运行完,再继续A的事务,即使A有异常B也不会回滚
PROPAGATION_MANDATORY:B方法运行在A方法中,A方法必须有事务,如果A没有事务,就抛出异常
PROPAGATION_NEVER:B不能不能在事务中运行,如果A存在事务,则抛出异常
PROPAGATION_NESTED :如果A存在事务,则在嵌套事务内执行,如果A没有事务,则执行自己的事务
与PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW另起一个事务,两个事务相互独立,而Nested的B事务提交时是要等A事务一块提交
isolation隔离级别:默认为Default
注解@Transactional实现原理
AnnotationDrivenBeanDefinitionParser解析器对应annotation-driven标签
//AnnotationDrivenBeanDefinitionParser.parse()方法节选
if ("aspectj".equals(mode)) {
// mode="aspectj"表示使用aspectj的方式比如CTW和LTW
registerTransactionAspect(element, parserContext);
}
else {
// mode="proxy"动态代理的方式
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
//configureAutoProxyCreator()方法的节选
//@Transactional注解对应的事务属性
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
//注册一个TransactionInterceptor
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
回到TransactionInterceptor获取TransactionAttribute,AnnotationTransactionAttributeSource是注解的事务属性资源实例
//获取事务属性
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// 不支持非public类型方法
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// 首先从specificMethod,也就是方法上获取@Transactional注解
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// 如果方法上没有则从方法所在的类上获取注解
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
//目标类和方法上都没有注解则从类的接口上找注解
if (specificMethod != method) {
//接口的方法上
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// 接口的类上
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
剩下的步骤和xml配置方式一样,对于@EnableTransactionManagement开启@Transactional注解使用
@EnableTransactionManagement(mode = AdviceMode.PROXY)
//通过@Import引用的ImportSelector会执行selectImports方法
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
//所以注册了两个组件:AutoProxyRegistrar,ProxyTransactionManagementConfiguration
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
}
}
//而ProxyTransactionManagementConfiguration组件又注册了几个熟悉的组件
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
//注册一个切面
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}