什么是Java的什么是动态代理 java中动态代理什么意思( 三 )

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进行方法植入,主要有四种:
  • 方法调用前拦截
  • 方法调用后拦截
  • 调用方法结束拦截
  • 抛出异常拦截
使用起来也非常简单,首先是在项目中添加AspectJ编译器插件 。

【什么是Java的什么是动态代理 java中动态代理什么意思】org.codehaus.mojoaspectj-maven-plugin1.5compiletest-compile1.61.6UTF-81.6truetrue
然后,编写一个方法,准备进行代理 。
@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等等,本质是使用的动态代理技术
总结起来就三点: