public class CglibCalculatorClass {/*** 计算两个数之和* @param num1* @param num2* @return*/public Integer add(Integer num1, Integer num2) {Integer result = num1 + num2;return result;}}
- 测试类
public class TestCglibProxyClass {public static void main(String[] args) {//目标对象CglibCalculatorClass target = new CglibCalculatorClass();System.out.println(target.getClass());//代理对象CglibCalculatorClass proxyClassObj = (CglibCalculatorClass) new CglibProxyFactory(target).getProxyInstance();System.out.println(proxyClassObj.getClass());//执行代理方法Integer result = proxyClassObj.add(1,2);System.out.println("相加结果:" + result);}}
- 输出结果
class com.example.java.proxy.cglib1.CglibCalculatorClassclass com.example.java.proxy.cglib1.CglibCalculatorClass$EnhancerByCGLIB$e68ff36c方法调用前,可以添加其他功能....方法调用后,可以添加其他功能....相加结果:3
四、静态织入在上文中,我们介绍的代理方案都是在代码运行时动态的生成class文件达到动态代理的目的 。
回到问题的本质,其实动态代理的技术目的,主要为了解决静态代理模式中当目标接口发生了扩展,代理类也要跟着一遍变动的问题,避免造成了工作伤的繁琐和复杂 。
在 Java 生态里面,还有一个非常有名的第三方代理框架,那就是AspectJ,AspectJ通过特定的编译器可以将目标类编译成class字节码的时候,在方法周围加上业务逻辑,从而达到静态代理的效果 。
采用AspectJ进行方法植入,主要有四种:
- 方法调用前拦截
- 方法调用后拦截
- 调用方法结束拦截
- 抛出异常拦截
【什么是Java的什么是动态代理 java中动态代理什么意思】
org.codehaus.mojo aspectj-maven-plugin1.5 compile test-compile 1.61.6UTF-8 1.6 true true
然后,编写一个方法,准备进行代理 。
@RequestMapping({"/hello"})public String hello(String name) {String result = "Hello World";System.out.println(result);return result;}
编写代理配置类
@Aspectpublic class ControllerAspect {/**** 定义切入点*/@Pointcut("execution(* com.example.demo.web..*.*(..))")public void methodAspect(){}/*** 方法调用前拦截*/@Before("methodAspect()")public void before(){System.out.println("代理 -> 调用方法执行之前......");}/*** 方法调用后拦截*/@After("methodAspect()")public void after(){System.out.println("代理 -> 调用方法执行之后......");}/*** 调用方法结束拦截*/@AfterReturning("methodAspect()")public void afterReturning(){System.out.println("代理 -> 调用方法结束之后......");}/*** 抛出异常拦截*/@AfterThrowing("methodAspect()")public void afterThrowing() {System.out.println("代理 -> 调用方法异常......");}}
编译后,hello方法会变成这样 。
@RequestMapping({"/hello"})public String hello(Integer name) throws SQLException {JoinPoint var2 = Factory.makeJP(ajc$tjp_0, this, this, name);Object var7;try {Object var5;try {//调用beforeAspectj.aspectOf().doBeforeTask2(var2);String result = "Hello World";System.out.println(result);var5 = result;} catch (Throwable var8) {Aspectj.aspectOf().after(var2);throw var8;}//调用afterAspectj.aspectOf().after(var2);var7 = var5;} catch (Throwable var9) {//调用抛出异常Aspectj.aspectOf().afterthrowing(var2);throw var9;}//调用returnAspectj.aspectOf().afterRutuen(var2);return (String)var7;}
很显然,代码被AspectJ编译器修改了,AspectJ并不是动态的在运行时生成代理类,而是在编译的时候就植入代码到class文件 。
由于是静态织入的,所以性能相对来说比较好!
五、小结看到上面的介绍静态织入方案,跟我们现在使用Spring AOP的方法极其相似,可能有的同学会发出疑问,我们现在使用的Spring AOP动态代理,到底是动态生成的还是静态织入的呢?
实际上,Spring AOP代理是对JDK代理和CGLIB代理做了一层封装,同时引入了AspectJ中的一些注解@pointCut、@after,@before等等,本质是使用的动态代理技术 。
总结起来就三点:
- 如果目标是接口的话,默认使用 JDK 的动态代理技术;
- 如果目标是类的话,使用 cglib 的动态代理技术;
- 引入了AspectJ中的一些注解@pointCut、@after,@before,主要是为了简化使用,跟AspectJ的关系并不大;
- DNF手游韩服可预约 DNF手游预约
- 却不知道到底在隔离什么 隔离到底是什么
- 发音为什么和闽南语不一样 闽南语和普通话发音区别
- 常任理事国为什么会有一票否决权 常任理事国一票否决权是什么意思
- 南京是江苏省会 南京是江苏省会 位于
- 这些动漫中的cp 动漫是什么
- 越是爱你的男人 越是爱你的男人越容易离开你
- 家用电烤箱排行榜 电烤炉什么牌子好
- 冰咖啡会减肥吗,日本有什么减肥咖啡
- 脚底下长痣代表什么