郑州网站建设排行榜/无锡网站推广公司
1、AOP组成
AOP包含两部分:AspectJ基于静态代理实现,在编译期生成代理类的方式
SpringAOP基于动态代理实现,动态代理又分为JDK动态代理和Cglib动态代理。
2、AOP实践:
AOP可以用在权限、日志等
我使用最多的就是这三方面,在日志方面需要将日志写到文件中,实现时将这部分独立出来,通过开启@Aspect注解、设定切面点@Pointcut(“execution(* com.tencent.modules.sys.controller….(…))”)获取到请求方法的入参、出参等信息进行存储。
在权限控制方面,用户通过toekn登录时,我们需要判断token是否失效的问题,在每个方法中加入token验证的方式很繁琐,通过AOP独立出来token验证的逻辑,这样在用户请求接口之前进行拦截请求,拦截到请求后获取到该请求中的token,然后对该token进行验证。
3、AOP解析:
3.1、AspectJ解析:
-
AspectJ是基于
静态代理
实现的,静态代理是在编译期
生成代理类的 -
AspectJ中存在一个acj编译器,该编译器的作用是将
aspect
类编译成class字节码,然后在java目标类编译时进行织入 -
其中静态代理是基于接口来实现的。
-
代理对象和实际对象都继承同一个接口,在代理对象中指向的是实际对象的实例,这样对外暴露的是代理对象而真正调用的是实际对象
-
静态代理比较好理解,需要被代理的类和代理类实现用一个接口,然后在代理类中调用真正实现类,并且静态代理的关系在编译器就已经确定了,而动态代理的关系是现在运行期间确定的。静态代理实现简单,适合于代理类较少的且确定的情况
3.2、SpringAOP解析:
3.2.1、JDK动态代理:
为了解决静态代理中 生成大量的代理类造成的冗余,提出了动态代理
-
JDK动态代理是在运行期生成代理类
-
JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM创建,JVM根据传进来的业务实现类对象以及方法名,动态创建一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用,我们做的只需要指定代理类的预处理、调用后操作即可。
-
静态代理和JDK动态代理都是基于接口实现的,对于那些没有提供接口只是提供实现类而言,就只能选择
cglib
动态代理。 -
JDK动态代理需要实现
invocationHandler
接口,重写invoke
方法,在invoke方法中,第一个参数为代理对象,第二个参数为代理对象的方法,第三个参数为方法中的参数
InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return null;}};
- JDK动态代理中需要使用的关键类有
java.lang.reflect.Proxy
类,在该类中有一个newProxyInstance
,该方法就是创建代理对象的方法,该方法中三个参数分别为:- ClassLoader为类加载器,
- Class<?>[]为需要代理的接口数组,
- InvocationHandler为执行处理器
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
简单实现逻辑如下:
创建两个接口A、B
public interface A {void getA();
}
public interface B {void getB();
}
创建一个实现类AImpl实现A、B两个接口并重写其中的方法
public class AImpl implements A,B{@Overridepublic void getA() {System.out.println("I am A");}@Overridepublic void getB() {System.out.println("I am B");}
}
创建代理工厂,创建目标对象
public class ProxyFactory {//目标对象private Object targetObject;/*** 用来生成代理对象* @return*/public Object creatProxy() {/*** 实例化三个参数*///类加载器ClassLoader classLoader = this.getClass().getClassLoader();//获取当前类型所实现的所有接口类型Class[] interfaces = targetObject.getClass().getInterfaces();//执行器InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/*** 这里写逻辑*///调用目标对象的目标方法Object result = method.invoke(targetObject, args);//返回目标对象的返回值return result;}};//通过调用Proxy中的newProxyInstance方法得到代理的对象Object proxyObject = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);return proxyObject;}public Object getTargetObject() {return targetObject;}public void setTargetObject(Object targetObject) {this.targetObject = targetObject;}
}
测试方法,调用代理工厂并设置需要代理的目标类AImpl。
public class Test {public static void main(String[] args) {Test test = new Test();test.tset1();}public void tset1() {//创建工厂ProxyFactory proxyFactory = new ProxyFactory();//设置目标对象AImpl,AImpl中实现了A、B两个接口proxyFactory.setTargetObject(new AImpl());A a = (A) proxyFactory.creatProxy();a.getA();B b = (B)proxyFactory.creatProxy();b.getB();}
}
3.2.2、Cglib动态代理:
由于jdk动态代理只能基于接口设计,而对于没有接口的情况,jdk方式解决不了,这就需要使用Cglib代理
- Cglib代理也是在运行期生成代理类
- cglib采用了非常底层的字节码技术,其原理是通过字节码技术为目标类创建子类,然后拦截所有父类中非
final
的方法的调用,顺势织入横切逻辑,从而完成动态代理的实现, - 实现方式是实现
MethodInterceptor
接口,重写intercept
方法,通过Enhancer
类指定要代理的目标对象,通过Enhancer类的回调方法来实现intercept代理。
public ClassA myCglibCreator() {Enhancer enhancer = new Enhancer();//设置要代理的目标对象enhancer.setSuperclass(ClassA.class);//设置回调方法,调用的方法其实就是intercept()方法enhancer.setCallback(this);//调用create()方法创建cglib动态代理对象ClassA classA = (ClassA) enhancer.create();return a;
}public interface MethodInterceptor extends Callback {public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable;
}
在intercept方法中的参数分别为:
1.Object: Cglib动态生成的代理类、
2. Method:类中被调用的方法,
3. Object[]:被调用方法的参数、
4. MethodProxy:生成的代理类的方法
简单实现逻辑如下:
1、创建需要被代理的类A,并创建一个非final的方法
public class ClassA {public String getString(){return "weerfwef";}
}
2、创建代理类实现MethodInterceptor,其中创建目标类的方法testCglib,并重写intercept方法
public class Cglib implements MethodInterceptor {public ClassA testCglib(){//初始化EnhancerEnhancer enhancer = new Enhancer();//设置要代理的目标对象enhancer.setSuperclass(ClassA.class);//设置回调方法,调用的方法其实就是intercept()方法enhancer.setCallback(this);//调用create()方法创建cglib动态代理对象ClassA classA = (ClassA) enhancer.create();return classA;}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {Object obj = methodProxy.invokeSuper(o,objects);if (obj!=null){//实现逻辑return obj.toString().toUpperCase();}return obj;}
}
3、测试类
public class Test {public static void main(String[] args) {ClassA proxy = new Cglib().testCglib();System.out.println(proxy.getString());}
}
4、总结
jdk动态代理和cglib动态代理的区别?
- jdk动态代理基于Java反射机制实现,必须要实现了接口的业务类才能生成代理对象。
- cglib代理基于ASM框架通过生成业务类的子类来实现。
- 基于cglib框架的优势是无需实现接口,我们只需要操作我们关系的类,性能比较高(相对与JDK动态代理来说在运行时性能更高,创建时速度较慢)。