我百度过AOP的实现方式好像有四种
-
第一种 静态AOP:在编译期,切面直接以字节码的形式编译到目标字节码文件中
优点:被织入的类性能不受影响。
缺点:不够灵活 -
第二种 动态AOP(JDK动态代理) :在运行期间,目标类加载后,为接口动态生成代理类,将切面植入到代理类中。
Java从1.3引入动态代理,实现原理是为被代理的业务接口生成代理类,将AOP逻辑写入到代理类中,在运行时动态织入AOP,使用反射执行织入的逻辑。主要实现方式依赖java.lang.reflect包下的InvocationHandler和Proxy类。
优点:java标准库原生支持,使用简单,无需引用额外的包。相对于静态AOP更灵活
缺点:带代理的类必须是接口,灵活性受到一些限制,使用反射会影响一些性能。 -
3.动态代码字节生成:在运行期间,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中。
CGLib是动态代码字节生成的实现,它封装字节码工具Asm,原理是在运行期间,目标字节码加载后,生成目标的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要的接口。
优点:没有接口也能织入,灵活性高
缺点:扩展类的实例方法为final时,则无法进行织入 -
4 自定义类加载器:在运行前,目标加载前,将切面逻辑加到目标字节码中.。
可以考虑javassist来实现,javassist是一个编辑字节码的框架,可以让你很简单的操作字节码。他可以在运行期间定义或修改Class。使用Javassist实现AOP的原理是在字节码加载前直接修改需要切入的方法。
有点:可以对绝大部分类织入。
缺点:如果用到了其他类加载器,则这些类将不被织入
本次写了动态JDK代理和字节码生成子类的方式实现AOP
贴类图
其中JDK的类是JDK动态代理实现的,CGLib的类是动态字节码生成实现的
现在开始实现,首先创建接口以及实现类(由于JDK动态代理只能代理接口,不能代理实例类,但是CGLib全都能代理,所以得创建一个借口用于测试JDK动态代理)
HelloAOP
package com.spring.aop.example;
/**
* 被代理的接口,基于jdk动态代理
*/
public interface HelloAOP {
//被动态的目标方法
public void show(String name);
}
HelloAOPImpl
package com.spring.aop.example;
/**
* aop的接口实现类
*/
public class HelloAOPImpl implements HelloAOP {
@Override
public void show(String name) {
System.out.println("===========hello,"+name+"=============");
}
}
创建完毕后,先写JDK的动态代理实现方式(代码很简单,我就不一一解释了,看注释就能看懂)
package com.spring.aop.example.dynamic;
import com.spring.aop.example.HelloAOP;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理目标为接口的JDK动态代理demo
* aop:aspectj-autoProxy proxy-target-class = false
*/
public class JDKDynamicProxy implements InvocationHandler {
//被代理的目标对象;
private HelloAOP helloAOP;
public JDKDynamicProxy(HelloAOP helloAOP){
this.helloAOP=helloAOP;
}
@Override //proxy 代理对象 method 目标所有的方法, 方法参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理,前置增强处理
before();
//代理方法执行,代理的目标实例,方法执行参数
Object result = method.invoke(helloAOP,args);
//动态代理,后置增强
after();
return result;
}
//生成代理对象并返回,
public HelloAOP getProxy(){
//生成代理对象,并返回
return (HelloAOP) Proxy.newProxyInstance(
//加载委托类
this.helloAOP.getClass().getClassLoader(),
//获取委托类里所有方法
this.helloAOP.getClass().getInterfaces(),
//代理对象执行的方法体
this
);
}
public void before(){
System.out.println("JDK前置增强");
}
public void after(){
System.out.println("JDK后置增加");
}
}
接着创建一个通用的封装过后的JDK动态代理类
package com.spring.aop.example.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 封装通用的JDK动态代理类
*
* 基于单例模式封装通用的jdk动态代理类
*/
public class JDKDynamicProxyBuild implements InvocationHandler {
//目标委托实例
private Object target;
/**
* 构造注入委托实例
* @param target
*/
public JDKDynamicProxyBuild(Object target){
this.target=target;
}
/**
* 生成动态代理类
* @param obj
* @param <T>
* @return
*/
public <T> T getProxy(Class<T> obj){
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(), //获取加载委托类
target.getClass().getInterfaces(), //获得委托类需要实现的所有接口
this //执行动态代理方法
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target,args);
after();
return result;
}
public void before(){
System.out.println("JDK动态代理封装----前置增强");
}
public void after(){
System.out.println("JDK动态代理封装----后置增强");
}
}
就这样JDK动态代理实现AOP就已经写完了,感觉不是很难,接下来写CGLib的实现方式
同上面一样,创建一个CGLib动态代理类。
package com.spring.aop.example.dynamic;
import com.spring.aop.example.HelloAOPImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 代理任意目标类的CGLIB动态代理DEMO
* CGLIB是一个强大、高性能的字节码生成库,它用于在运行是拓展,java类的实现接口;
* 本质上他是通过动态的生成了一个子类去覆盖所要代理的类(非final修饰的类和方法)。
*/
public class CGLibDynamicProxy implements MethodInterceptor {
//代理目标实例
private HelloAOPImpl helloAOPImpl;
//创建代理实例并返回
public Object getInstance(HelloAOPImpl helloAOPImpl){
this.helloAOPImpl=helloAOPImpl;
/**
* Enhancer是一个非常重要的类,它允许为非接口类型创建一个java代理,
* Enhancer动态的创建给定类的子类,并且拦截代理类的所有方法。
* 和jdk动态代理不一样的是不管是接口还是类他都能正常工作。
* 而jdk动态代理,只能代理接口
*/
//Enhancer动态代理对象
Enhancer enhancer = new Enhancer();
//给动态代理对象设置指定的代理类
enhancer.setSuperclass(HelloAOPImpl.class);
//设置回调
enhancer.setCallback(this);
//创建并返回的代理类的实例
return enhancer.create();
}
@Override //obj 代理对象, method 委托类方法,arg 方法参数,methodproxy代理方法的methodProxy对象
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
//前置增强
before();
//通过代理对象调用父类的方法
Object result = methodProxy.invokeSuper(obj,arg);
//后置增强
after();
return result;
}
public void before(){
System.out.println("CGLIB动态代理------前置增强");
}
public void after(){
System.out.println("CGLIB动态代理------后置增强");
}
}
在创建一个通用的封装过后的类
package com.spring.aop.example.dynamic;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 封装通用的CGLIB动态代理类
*/
public class CGLIBDynamicProxyBuild implements MethodInterceptor {
//代理类实例
private static CGLIBDynamicProxyBuild dynamicProxyBuild = new CGLIBDynamicProxyBuild();
/**
* 私有的构造,外界无法创建动态代理类实例
*/
private CGLIBDynamicProxyBuild(){ }
/**
* 单例模式,饿汉模式:类加载速度慢,获取对象速度快,线程安全,不能延迟加载
* @return
*/
public static CGLIBDynamicProxyBuild getInstance(){
return dynamicProxyBuild;
}
//创建动态代理类实例
@SuppressWarnings("unchecked")
public <T> T getProxy(Class<T> cls){
return (T) Enhancer.create(cls,this);
}
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
before();
Object result = methodProxy.invokeSuper(target,args);
after();
return result;
}
public void before(){
System.out.println("CGLIB动态代理封装----前置增强");
}
public void after(){
System.out.println("CGLIB动态代理封装----后置增强");
}
}
这样就写完了,其中织入过程已经用代码写的很清楚了,直接测试就行了 。
package com.spring.aop;
import com.spring.aop.example.HelloAOP;
import com.spring.aop.example.HelloAOPImpl;
import com.spring.aop.example.dynamic.CGLIBDynamicProxyBuild;
import com.spring.aop.example.dynamic.CGLibDynamicProxy;
import com.spring.aop.example.dynamic.JDKDynamicProxy;
import com.spring.aop.example.dynamic.JDKDynamicProxyBuild;
public class Test {
@SuppressWarnings(value = "unchecked")
public static void main(String[] args) {
//创建helloAop对象,由于JDK只能代理接口,所有需要用实现类实现接口的方式创建对象
HelloAOP helloAOP = new HelloAOPImpl();
//生成代理类,代理的目标对象为HelloAop,生成它的代理类
JDKDynamicProxy proxy = new JDKDynamicProxy(helloAOP);
//代理类调用目标代理对象的方法,并传入参数
proxy.getProxy().show("张三");
System.out.println();
//创建委托类实例
HelloAOPImpl helloAOPImpl = new HelloAOPImpl();
//创建CGLib动态代理实例
CGLibDynamicProxy proxy1 = new CGLibDynamicProxy();
//动态创建helloaopimpl动态代理的代理类,
// CGLIB创建代理类的原理是创建一个以委托类作为目标对象的子类,
// 并重写父类的所有非fanil方法,子类会拦截父类的非final所有方法,顺便织入横切逻辑
//这里创建cglibProxy代理对象作为 helloAOPImpl类的子类,并拦截父类的所有方法
Object cglibProxy = proxy1.getInstance(helloAOPImpl);
//代理类向上转型为父类
HelloAOPImpl realProxy = (HelloAOPImpl) cglibProxy;
//子类重写父类的方法再向上转型为父类,所以父类调用的就是子类的方法,而这个方法已经被增强了
realProxy.show("李四");
System.out.println();
//创建代理对象
HelloAOP helloAOP1 = new HelloAOPImpl();
//创建代理实例
JDKDynamicProxyBuild rebuild = new JDKDynamicProxyBuild(helloAOP1);
//JDK动态生成代理目标对象的委托类,
HelloAOP proxy2 = rebuild.getProxy(HelloAOP.class);
proxy2.show("王五");
System.out.println();
//创建委托类实例
CGLIBDynamicProxyBuild rebuild2 = CGLIBDynamicProxyBuild.getInstance();
//生成代理类的委托类
HelloAOPImpl helloAOPImpl2 = rebuild2.getProxy(HelloAOPImpl.class);
//调用方法
helloAOPImpl2.show("赵六");
}
}