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方法了