Spring AOP 原理
静态代理
public class ProxyDemo { public static void main(String[] args) { RealImage realImage = new RealImage(); ProxyImage proxyImage = new ProxyImage(realImage); proxyImage.doSomething(); } } interface Image { void doSomething(); } class RealImage implements Image { @Override public void doSomething() { System.out.println("Real image"); } } class ProxyImage implements Image { private RealImage realImage; public ProxyImage(RealImage realImage) { this.realImage = realImage; } @Override public void doSomething() { System.out.println("proxy start"); realImage.doSomething(); System.out.println("proxy end"); } }
打印结果:
proxy start Real image proxy end
JDK 动态代理(基于接口)
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyDemo { public static void main(String[] args) { Target target = new TargetImpl(); TargetIH targetIH = new TargetIH(target); Class<?> clazz = target.getClass(); Target proxyInstance = (Target) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), targetIH); proxyInstance.doSomething(); proxyInstance.doSomethingElse(); } } interface Target { void doSomething(); void doSomethingElse(); } class TargetImpl implements Target { @Override public void doSomething() { System.out.println("TargetImpl doSomething"); } @Override public void doSomethingElse() { System.out.println("TargetImpl doSomethingElse"); } } class TargetIH implements InvocationHandler { private Object target; public TargetIH(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) { System.out.println("proxy start"); Object result = null; try { result = method.invoke(target, args); } catch (Exception e) { // do something } System.out.println("proxy end"); return result; } }
打印:
proxy start TargetImpl doSomething proxy end proxy start TargetImpl doSomethingElse proxy end
CGLIB
CGLIB (Byte Code Generation Library is high level API to generate and transform Java byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept field access)动态代理,不需要有接口
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency>
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 ProxyDemo { public static void main(String[] args) { TargetMI interceptor = new TargetMI(); Enhancer e = new Enhancer(); e.setSuperclass(Target.class); e.setCallback(interceptor); Target proxyInstance = (Target) e.create(); proxyInstance.doSomething(); } } class Target { public void doSomething() { System.out.println("doSomething"); } } class TargetMI implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("proxy start"); Object retValFromSuper = proxy.invokeSuper(obj, args); System.out.println("proxy end"); return retValFromSuper; } }
打印:
proxy start doSomething proxy end
Spring AOP
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.3.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.10</version> </dependency> </dependencies>
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> <context:annotation-config /> <context:component-scan base-package="cn.zno.*" /> </beans>
package cn.zno.foo; 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; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; public class ProxyDemo { public static void main(String[] args) { @SuppressWarnings("resource") ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); Target target = (Target) ctx.getBean(Target.class); target.doSomething(); target.doSomethingElse(); } } interface Target { public void doSomething(); public void doSomethingElse(); } @Component class TargetImpl implements Target { @Override public void doSomething() { System.out.println("doSomething"); } @Override public void doSomethingElse() { System.out.println("doSomethingElse"); } } @Component // 需要注册到bean工厂,否则不会生效 @Aspect // 需要配置Spring AOP class TargetInterceptor { @Pointcut("execution(* doSomething(..)) || execution(* doSomethingElse(..))") // the pointcut(target method) signature private void anysdf() { System.out.println("pointcut signature"); } @Before(value = "anysdf()") public void before(JoinPoint joinPoint) { System.out.println("Before"); } @After("anysdf()") public void after() { System.out.println("After"); } }
打印:
Before doSomething After Before doSomethingElse After