1.jdk dynamic proxy
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; AService public interface { public void barA(); public void fooA(String _msg); }
Java dynamic proxy is to generate a class to implement the interface, and then there is an object reference handler in it.
2.cglib dynamic proxy
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) { //Set the subclass to be created enhancer.setSuperclass(clazz); enhancer.setCallback(this); / / Dynamically create subclass instances through bytecode technology 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); //Create a proxy class by dynamically generating subclasses bn.fooA("nimei"); } }
cglib is to create a subclass to implement this class and override the parent class method
3.Spring aop
test code
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"> <!--Configure all methods of all classes or interfaces under the com.spring.service package--> <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("Create TestAspect instance"); } ////Post notification: After the target method (whether an exception occurs or not), the notification executed, public void doAfter(JoinPoint jp) { System.out.println("doAfter 被调用: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); } //Bad winding notification: need to carry parameters of type ProceedingJoinPoint // Surround notification is similar to the whole process of dynamic proxy: the parameter of type ProceedingJoinPoint can decide whether to execute the target method //And the surround notification must have a return value, which is the return value of the target method. public Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("doAround is called"); long time = System.currentTimeMillis(); Object retVal = pjp.proceed(); time = System.currentTimeMillis() - time; return retVal; } //// Declare the method as a pre-advice: execute before the target method starts public void doBefore(JoinPoint jp) { System.out.println("doBefore 被调用: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); } //The code that will be executed when the target method fails, //The exception object can be accessed, and the notification code can be executed when a specific exception occurs //As the following Exception ex, if it is specified as NullpointerException ex, the notification code will not be executed 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(); } }
Source code analysis:
1. First register an AspectJAwareAdvisorAutoProxyCreator post-processor in registerBeanPostProcessors(beanFactory) (registered post-processor method) in the refresh method of AbstractApplicationContext
2. AspectJAwareAdvisorAutoProxyCreator inherits AbstractAutoProxyCreator, AbstractAutoProxyCreator implements the BeanPostProcessor interface, when calling the postProcessAfterInitialization method
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); //create proxy class 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. If a bean is configured with aop notification interception, an instance of the bean is generated to generate a proxy class, which records the notification class information
2. Next, let's focus on the invoke method of JdkDynamicAopProxy