1.jdk动态代理
package com.jhuc.aop; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { AService aa=(AService) Proxy.newProxyInstance(AService.class.getClassLoader(), new Class[]{AService.class}, new ProxyA(new AServiceImpl())); aa.fooA("aha"); } }
package com.jhuc.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class ProxyA implements InvocationHandler{ private Object obj; public ProxyA(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(obj, args); } }
package com.jhuc.aop; public interface AService { public void barA(); public void fooA(String _msg); }
java动态代理就是生成一个类来实现接口,然后里面有一个对象引用handler。
2.cglib动态代理
package com.jhuc.aop; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor{ Enhancer enhancer = new Enhancer(); public <T> Object getProxy(Class<T> clazz) { //设置需要创建的子类 enhancer.setSuperclass(clazz); enhancer.setCallback(this); //通过字节码技术动态创建子类实例 return enhancer.create(); } @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable{ System.out.println("haha"); return arg3.invokeSuper(arg0, arg2); } }
package com.jhuc.aop; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { AService aa=(AService) Proxy.newProxyInstance(AService.class.getClassLoader(), new Class[]{AService.class}, new ProxyA(new AServiceImpl())); aa.fooA("aha"); CglibProxy proxy = new CglibProxy(); AService bn=(AServiceImpl) proxy.getProxy(AServiceImpl.class); //通过动态生成子类的方式创建代理类 bn.fooA("nimei"); } }
cglib是创建一个子类去实现这个类,覆盖父类方法
3.Spring aop
测试代码
aopbean.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <aop:config> <aop:aspect id="TestAspect" ref="aspectBean"> <!--配置com.spring.service包下所有类或接口的所有方法--> <aop:pointcut id="businessService" expression="execution(* com.jhuc.aop.*.*(..))" /> <aop:before pointcut-ref="businessService" method="doBefore"/> <aop:after pointcut-ref="businessService" method="doAfter"/> <aop:around pointcut-ref="businessService" method="doAround"/> <aop:after-throwing pointcut-ref="businessService" method="doThrowing" throwing="ex"/> </aop:aspect> </aop:config> <bean id="aspectBean" class="com.jhuc.aop.TestAspect" /> <bean id="aService" class="com.jhuc.aop.AServiceImpl"></bean> <!-- <bean id="bService" class="com.jhuc.aop.BServiceImpl"></bean> --> </beans>
package com.jhuc.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainTest { public static void main(String[] args) throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("aopbean.xml"); AService obj = (AService) context.getBean("aService"); obj.fooA("ggg"); } }
package com.jhuc.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class TestAspect { public TestAspect(){ System.out.println("创建TestAspect实例"); } ////后置通知:在目标方法之后(无论是否发生异常),执行的通知, public void doAfter(JoinPoint jp) { System.out.println("doAfter 被调用: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); } //坏绕通知:需要携带ProceedingJoinPoint类型的参数 //环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法 //且环绕通知必须有返回值,返回值即目标方法的返回值。 public Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("doAround 被调用"); long time = System.currentTimeMillis(); Object retVal = pjp.proceed(); time = System.currentTimeMillis() - time; return retVal; } ////声明该方法是一个前置通知:在目标方法开始之前执行 public void doBefore(JoinPoint jp) { System.out.println("doBefore 被调用: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); } //在目标方法出现异常时会执行的代码, //可以访问到异常对象,且可以指定在出现特定异常时在执行通知代码 //如下面Exception ex,若是指定为NullpointerException ex就不会执行通知代码 public void doThrowing(JoinPoint jp, Exception ex) { System.out.println("doThrowing 被调用 " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName() + " throw exception"); } }
package com.jhuc.aop; public class AServiceImpl implements AService { public void barA() { System.out.println("AServiceImpl.barA()"); } public void fooA(String _msg) throws Exception { System.out.println("AServiceImpl.fooA(msg:" + _msg + ")"); throw new Exception(); } }
源码分析:
1.首先在AbstractApplicationContext的refresh方法中的registerBeanPostProcessors(beanFactory)(注册后置处理器方法)中注册一个AspectJAwareAdvisorAutoProxyCreator后置处理器
2.AspectJAwareAdvisorAutoProxyCreator继承了AbstractAutoProxyCreator,AbstractAutoProxyCreator实现了BeanPostProcessor接口,在调用postProcessAfterInitialization方法时
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.containsKey(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); //创建代理类 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
1.如果一个bean被配置了aop通知拦截,在生成这个bean的实例是生成一个代理类,里面记录了通知类信息
2.接下来重点看JdkDynamicAopProxy 的invoke方法了