常用AOP代理形式
AOP常见有静态代理和动态代理
静态代理代表为AspectJ;
动态代理有jdk动态代理, cglib动态代理。
静态代理
AspectJ是静态代理的增强, 即编译时生成代理类, 也成为编译时增强。性能较好。 不过由于需要特定的编译器进行处理。
动态代理
动态代理是每次运行的时候生成代理AOP代理类,不会修改字节码文件。代理对象创建在内存中。
由于是在运行的时候生成代理,故性能稍差一点。
JDK动态代理实例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author imyzt
* @date 2019/1/17 9:51
* @description JDK动态代理演示
*/
public class JdkDynamicProxyDemo {
public static void main(String[] args) {
// 创建需要被代理的实例对象
JdkDynamicProxyClass jdkDynamicProxyClass = new JdkDynamicProxyClass();
JdkDynamicProxyInvocationHandler invocationHandler =
new JdkDynamicProxyInvocationHandler(jdkDynamicProxyClass);
// 增强代理类
// Proxy.newProxyInstance();
JdkDynamicProxyInterface proxyInstance = (JdkDynamicProxyInterface) Proxy.newProxyInstance(
jdkDynamicProxyClass.getClass().getClassLoader(),
jdkDynamicProxyClass.getClass().getInterfaces(),
invocationHandler);
// 执行被增强的方法
proxyInstance.proxyMethod();
}
}
interface JdkDynamicProxyInterface {
void proxyMethod();
}
class JdkDynamicProxyClass implements JdkDynamicProxyInterface {
@Override
public void proxyMethod() {
System.out.println("JDK Dynamic Proxy Method is running");
}
}
class JdkDynamicProxyInvocationHandler implements InvocationHandler {
private Object target;
public JdkDynamicProxyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println("execute before JDK Dynamic Method = " + name);
Object invoke = method.invoke(target, args);
System.out.println("execute after JDK Dynamic Method = " + name);
return invoke;
}
}
运行结果展示
CGLIB 动态代理
/**
* @author imyzt
* @date 2019/1/17 10:05
* @description CGLIB 动态代理演示
*/
public class CglibDynamicProxyDemo {
public static void main(String[] args) {
CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CglibDynamicClass.class);
enhancer.setCallback(cglibDynamicProxy);
CglibDynamicClass cglibDynamicClass = (CglibDynamicClass) enhancer.create();
String yyy = cglibDynamicClass.proxyMethod("yyy");
System.out.println(yyy);
}
}
class CglibDynamicClass {
public String proxyMethod(String message){
System.out.println("hello! you say " + message);
return message;
}
}
class CglibDynamicProxy implements MethodInterceptor {
@Override
public Object intercept(Object proxyClass, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
String name = method.getName();
System.out.println("execute before CGLIB Dynamic Method = " + name);
Object invoke = **methodProxy.invokeSuper**(proxyClass, args);
System.out.println("execute after CGLIB Dynamic Method = " + name);
return invoke;
}
}
运行结果展示
Spring AOP
Spring AOP在使用的时候会判断,如果需要代理的类实现了接口, 则会使用JDK代理,如果没有实现接口, 则使用CGLIB代理。
JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类(通过修改字节码来实现代理)。
注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
文章中部分内容转载自掘金-年糕妈妈技术团队