Spring AOP(面向切面编程)

本文深入解析Spring AOP的多种实现方式,包括基于接口的AOP、自动代理、基于AspectJ的配置以及注解驱动的AOP。通过示例代码详细说明了如何配置代理,以及Spring内部如何生成和处理代理对象。
摘要由CSDN通过智能技术生成

基于接口的AOP

代理接口的所有方法

配置:

<bean id="msgServerImpl" class="com.canwin.aop.MsgServerImpl"/>
<bean id="beforeAdvice" class="com.canwin.aop.BeforeAdvice"/>
<!--简单aop,需要使用代理bean-->
<bean id="proxyMsgServer" class="org.springframework.aop.framework.ProxyFactoryBean">
	<!-- 代理接口 -->
	<property name="proxyInterfaces">
		<list>
			<value>com.canwin.aop.MsgServer</value>
		</list>
	</property>
	<!-- 代理的实现类 -->
	<property name="target" ref="msgServerImpl"/>
	<!-- 配置拦截器 -->
	<property name="interceptorNames">
		<list>
			<value>beforeAdvice</value>
		</list>
	</property>
</bean>

接口:

package com.canwin.aop;

public interface MsgServer {
    public String sendMsg();
    public String getMsg();
}

接口的实现:

package com.canwin.aop;

public class MsgServerImpl implements MsgServer{
    public String sendMsg() {
        return "HelloWorld";
    }

    public String getMsg() {
        return "GetMsg";
    }
}

通知类:

package com.canwin.aop;

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

public class BeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("++++++++++++++++++++++++");
        System.out.println(method.getName() + ": before");
        System.out.println("++++++++++++++++++++++++");
    }
}

使用:

public static void main(String[] args){
    ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
	//要获取代理Bean
    MsgServer msgServer = (MsgServer)context.getBean("proxyMsgServer");
    System.out.println(msgServer.sendMsg());
    System.out.println(msgServer.getMsg());
}

代理接口的指定方法

配置:

<bean id="msgServerImpl" class="com.canwin.aop.MsgServerImpl"/>
<bean id="beforeAdvice" class="com.canwin.aop.BeforeAdvice"/>
<bean id="proxyMsgServer" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
        <list>
            <value>com.canwin.aop.MsgServer</value>
        </list>
    </property>

    <property name="target" ref="msgServerImpl"/>
    <property name="interceptorNames">
        <list>
			<!-- Advisor的ID -->
            <value>msgAdvisor</value>
        </list>
    </property>
</bean>
<!-- 配置Advisor,其中可以指定Advice和需要代理的方法 -->
<bean id="msgAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    <property name="advice" ref="beforeAdvice"/>
    <property name="mappedName" value="sendMsg"/>
</bean>

其他不需要变。

自动代理

配置:

<bean id="msgServerImpl" class="com.canwin.aop.MsgServerImpl"/>
<bean id="beforeAdvice" class="com.canwin.aop.BeforeAdvice"/>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="interceptorNames">
        <list>
            <value>beforeAdvice</value>
        </list>
    </property>
    <property name="beanNames" value="*ServerImpl"/>
</bean>

使用:

public static void main(String[] args){
    ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
	// 直接获取被代理的Bean
    MsgServer msgServer = context.getBean(MsgServer.class);
    System.out.println(msgServer.sendMsg());
    System.out.println(msgServer.getMsg());
}

其他不需要变。

自动代理指定的方法

<bean id="msgServerImpl" class="com.canwin.aop.MsgServerImpl"/>
<bean id="beforeAdvice" class="com.canwin.aop.BeforeAdvice"/>
<bean id="sendAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
   <property name="advice" ref="beforeAdvice"/>
   <property name="pattern" value="com.canwin.aop.*.send.*"/>
</bean>

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

其他不需要变

基于AspectJ的配置

加入依赖:

<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.9.5</version>
</dependency>

package com.canwin.aop;
//不需要接口
public class MsgServer{
    public String sendMsg() {
        return "HelloWorld";
    }

    public String getMsg() {
        return "GetMsg";
    }
}

Aspect:

package com.canwin.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class SendAspect {
	//定义切点
    @Pointcut("execution(* com.canwin.aop..send*(..))")
    public void send(){}
    @Pointcut("execution(* com.canwin..get*(..))")
    public void afterGet(){}

	// 定义通知
    @Before("send()")
    public void sendAdvice(JoinPoint joinPoint){
        System.out.println("++++++++++++++++++++++++");
        System.out.println(joinPoint.getStaticPart() + ": before");
        System.out.println("++++++++++++++++++++++++");
    }
    @After("afterGet()")
    public void afterGet(JoinPoint joinPoint){
        System.out.println("++++++++++++++++++++++++");
        System.out.println(joinPoint.getStaticPart() + ": after");
        System.out.println("++++++++++++++++++++++++");
    }
}

配置:

<bean id="msgServerImpl" class="com.canwin.aop.MsgServer"/>
<aop:aspectj-autoproxy/>
<bean class="com.canwin.aop.SendAspect"/>

使用:

public static void main(String[] args){
    ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
    MsgServer msgServer = context.getBean(MsgServer.class);
    System.out.println(msgServer.sendMsg());
    System.out.println(msgServer.getMsg());
}

基于<aop:config />的配置

Aspect:

package com.canwin.aop;

import org.aspectj.lang.JoinPoint;

public class SendAspect {

    public void sendAdvice(JoinPoint joinPoint){
        System.out.println("++++++++++++++++++++++++");
        System.out.println(joinPoint.getStaticPart() + ": before");
        System.out.println("++++++++++++++++++++++++");
    }

    public void afterGet(JoinPoint joinPoint){
        System.out.println("++++++++++++++++++++++++");
        System.out.println(joinPoint.getStaticPart() + ": after");
        System.out.println("++++++++++++++++++++++++");
    }
}

连接点:

public class MsgServer{
    public String sendMsg() {
        return "HelloWorld";
    }

    public String getMsg() {
        return "GetMsg";
    }
}

配置:

<bean id="msgServerImpl" class="com.canwin.aop.MsgServer"/>
<bean id="myAspect" class="com.canwin.aop.SendAspect"/>
<aop:config>
    <aop:pointcut id="before" expression="execution(* com.canwin.aop..send*(..))"/>
    <aop:pointcut id="after" expression="execution(* com.canwin.aop..get*(..))"/>
    <aop:aspect ref="myAspect">
        <aop:before method="sendAdvice" pointcut-ref="before"/>
        <aop:after method="afterGet" pointcut-ref="after"/>
    </aop:aspect>
</aop:config>

源码分析:

以下内容参考博客:https://javadoop.com/post/spring-aop-source

使用自动生成代理bean的DefaultAdvisorAutoProxyCreator

DefaultAdvisorAutoProxyCreator是一个BeanPostProcessor,所以在初始化bean的后会调用它的beanProcessAfterInitialization()方法,
该方法在其父类:AbstractAutoProxyCreator这一层被复写:

DefaultAdvisorAutoProxyCreator.postProcessAfterInitialization(Object bean, String beanName);
->DefaultAdvisorAutoProxyCreator.wrapIfNecessary(Object bean, String beanName, Object cacheKey);
  ->specificInterceptors = DefaultAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);//返回匹配bean的所有advisor,advice,interceptor
  ->createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));//创建代理,TargetSource:包装被代理Bean
  	//createProxy()
    ->ProxyFactory proxyFactory = new ProxyFactory();//创建ProxyFactory
	->if (!proxyFactory.isProxyTargetClass()){ // 是否配置了proxy-target-class="true",是的话,无论有没有接口,都是用CGLIB来生成代理
		  if (shouldProxyTargetClass(beanClass, beanName)) {
			 proxyFactory.setProxyTargetClass(true);
		  }
		  else {
			  evaluateProxyInterfaces(beanClass, proxyFactory);
			  ->//如果bean有接口,那么调用proxyFactory.addInterface(),加入接口的Class<?>对象
			    //如果bean没有接口,那么proxyFactoty.setProxyTargetClass(true)
		   }
	  }
	->Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); //返回Advisor数组,如果是Advice或者Interceptor对象,会被包装成Advisor对象
	->proxyFactory.addAdvisors(advisors);
	->return proxyFactory.getProxy(getProxyClassLoader());
	  ->AopProxy aopProxy = this.createAopProxy();
	    ->AopProxyFactory proxyFactory = getAopProxyFactory();
		  ->return this.aopProxyFactory; //org.springframework.aop.framework.ProxyCreatorSupport的构造函数中初始化aopProxyFactory为一个DefaultAopProxyFactory;
		->return proxyFactory.createAopProxy(this);
		  //createProxy();如果bean实现了多个自定义接口,就会使用JDK自动代理,否则使用CGLIB;如果设置了proxy-target-class="true",也会使用CGLIB
		  ->if optimize == false && proxy-target-class==true && 没有接口
		    	return new JdkDynamicAopProxy(config);
			else{
				return ObjenesisCglibAopProxy(config);
			}
	  ->return aopProxy.getProxy(classLoader);
//JdkDynamicAopProxy
JdkDynamicAopProxy.getProxy(config);
	// 这部很重要,就是去找接口 我们看到最终代理的接口就是这里返回的所有接口们(除了我们自己的接口,还有Spring默认的一些接口)  大致过程如下:
	//1、获取目标对象自己实现的接口们(最终肯定都会被代理的)
	//2、是否添加`SpringProxy`这个接口:目标对象实现对就不添加了,没实现过就添加true
	//3、是否新增`Adviced`接口,注意不是Advice通知接口。 实现过就不实现了,没实现过并且advised.isOpaque()=false就添加(默认是会添加的)
	//4、是否新增DecoratingProxy接口。传入的参数decoratingProxy为true,并且没实现过就添加(显然这里,首次进来是会添加的)
	//5、代理类的接口一共是目标对象的接口+上面三个接口SpringProxy、Advised、DecoratingProxy(SpringProxy是个标记接口而已,其余的接口都有对应的方法的)
->Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
->this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
  //第三个入参为this,表示处理器是自己(JdkDynamicAopProxy实例)
  //生成的代理类中,有一个字段h,指向this,调用目标对象所实现的接口定义的方法,都将交给JdkDynamicAopProxy对象来处理,具体处理方式是调用JdkDynamicAopProxy.invoke()方法
->return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); //生成了代理类
//JdkDynamicAopProxy.invoke()
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    Class var8;
    try {
		//是否是equals()方法
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            Boolean var18 = this.equals(args[0]);
            return var18;
        }
		//是否是hashCode()方法
        if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            Integer var17 = this.hashCode();
            return var17;
        }
		//如果方法不是DecoratingProxy的方法
        if (method.getDeclaringClass() != DecoratingProxy.class) {
            Object retVal;
			//如果方法是Advised接口的方法
            if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                return retVal;
            }
    		//暴露代理对象
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            target = targetSource.getTarget();
            Class<?> targetClass = target != null ? target.getClass() : null;
			//获取与该方法匹配的所有拦截器和通知
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            if (chain.isEmpty()) {
				//没有匹配的拦截器或通知时,直接调用目标方法
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            } else {
				//匹配到了拦截器或通知,调用增强了的目标方法
                MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                retVal = invocation.proceed();
            }

            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                retVal = proxy;
            } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
            }

            Object var12 = retVal;
            return var12;
        }

        var8 = AopProxyUtils.ultimateTargetClass(this.advised);
    } finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }

        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }

    }

    return var8;
}

基于注解

为了开启@AspectJ注解,一个使用<aop:aspectj-autoproxy/>,一个是使用@EnableAspectJAutoProxy。它们的原理是一样的

使用<aop:aspectj-autoproxy/>,最终会在spring容器中注册一个AnnotationAwareAspectJAutoProxyCreatorbean,而该类也是一个BeanPostProcessor:

所以原理同前面讲的也差不多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值