基于接口的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>
源码分析:
使用自动生成代理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容器中注册一个AnnotationAwareAspectJAutoProxyCreator
bean,而该类也是一个BeanPostProcessor
:
所以原理同前面讲的也差不多。