Java动态代理(java动态代理的实现方式)

  本篇文章为你整理了Java动态代理(java动态代理的实现方式)的详细内容,包含有java动态代理原理 java动态代理的实现方式 java动态代理使用场景 Java动态代理 Java动态代理,希望能帮助你了解 Java动态代理。

  这周工作比较忙,在学习上面就温习了一下动态代理,以前也看过这块的知识,但是一直没有动手去写下代码。学习就是这样,不动手写一写总有种没有掌握的感觉,记录下这个学习过程
 

  动态代理有什么用呢? 它的作用就是增强,对于一个方法,我想在执行它之前执行另外一个log方法,那我可以修改代码,我可以直接去加,但是假如有很多方法都需要加这个log,那工作量就大了,我们可以用动态代理来加上这个log方法,然后通过代理来调用原来的方法,达到不修改原来方法,增加功能的目的。
 

  动态代理实现上有两种方法JDK动态代理和CGLib动态代理,下面我们分别来演示一下

  JDK动态代理

  JDK动态代理是JDK自带的,通过反射来实现,需要基于接口来做,
 

  首先我们定义一个需要代理的接口和它的实现类

  

public interface IHelloWorld {

 

   String say();

  public class HelloWorld implements IHelloWorld{

   @Override

   public String say() {

   System.out.println("this is helloworld");

   return "Hello World";

  

 

  我们需要在调用say前面和后面都加些日志,直接上动态代理的代码

  

public class DynamicProxy implements InvocationHandler {

 

   private Object target;

   public DynamicProxy(Object target){

   this.target = target;

   private void before(){

   System.out.println("this is before");

   private void after(){

   System.out.println("this is after");

   @Override

   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

   before();

   Object result = method.invoke(this.target, args);

   after();

   return result;

  

 

  在main方法中加入如下代码来调用这个动态代理

  

 IHelloWorld helloWorld = new HelloWorld();

 

   DynamicProxy dynamicProxy1 = new DynamicProxy(helloWorld);

   IHelloWorld helloWorldProxy = (IHelloWorld) Proxy.newProxyInstance(helloWorld.getClass().getClassLoader(),

   helloWorld.getClass().getInterfaces(), dynamicProxy1);

   String hello = helloWorldProxy.say();

  

 

  输出如下

  

this is before

 

  this is helloworld

  this is after

  

 

  我们可以看到调用helloWorldProxy.say()方法后,
 

  先调用了before(),然后调用helloWorld的say(), 然后再调用了after().
 

  也就是DynamicProxy里面的invoke方法里面的顺序来执行。
 

  这样写代码有点复杂了
 

  IHelloWorld helloWorld1 = (IHelloWorld) Proxy.newProxyInstance(helloWorld.getClass().getClassLoader(),
 

  helloWorld.getClass().getInterfaces(), dynamicProxy1);
 

  在黄勇的《架构探险-从零开始写Java Web框架》中又包装了一下,在DynamicProxy中定义了这个方法

  

@SuppressWarnings("unchecked")

 

   public T T getProxy()

   return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),

   target.getClass().getInterfaces(), this);

  

 

  调用起来简单明了很多

  

 IHelloWorld helloWorld = new HelloWorld();

 

   DynamicProxy dynamicProxy1 = new DynamicProxy(helloWorld);

   IHelloWorld helloWorldProxy = dynamicProxy1.getProxy();

   helloWorldProxy.say();

  

 

  如果我们又有个方法需要加before()和after(),那么就可以直接用

  

 IUserService userService = new UserService();

 

   DynamicProxy dynamicProxy = new DynamicProxy(userService);

   IUserService userServiceProxy = dynamicProxy.getProxy();

   userServiceProxy.send();

  

 

  这就是JDK动态代理,缺点就是必须基于接口,
 

  也就是必须这样写
 

  IUserService userServiceProxy = dynamicProxy.getProxy();
 

  直接写
 

  UserService userServiceProxy = dynamicProxy.getProxy();
 

  会报如下的转化错误
 

  “java.lang.ClassCastException: class jdk.proxy1.$Proxy0 cannot be cast to class ken.proxy.demo.UserService”

  CGLib动态代理

  CGLib动态代理需要引入一个包

  

 dependency 

 

   groupId cglib /groupId

   artifactId cglib /artifactId

   version 3.3.0 /version

   /dependency

  

 

  代码比较简单,直接贴代码出来

  

public class CGLibProxy implements MethodInterceptor {

 

   private void before(){

   System.out.println("this is before");

   private void after(){

   System.out.println("this is after");

   public T T getProxy(Class T cls) {

   return (T) Enhancer.create(cls,this);

   @Override

   public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

   before();

   Object result = methodProxy.invokeSuper(obj, args);

   after();

   return result;

  

 

  调用代码

  

CGLibProxy cgLibProxy = new CGLibProxy();

 

  HelloWorld helloWorld = cgLibProxy.getProxy(HelloWorld.class);

  helloWorld.say();

  

 

  输出和JDK动态代理一样。 它不要求HelloWorld一定去实现某个接口,相对比JDK动态代理要好,据说许多框架都用到了它。
 

  这里遇到个坑, 我用Java19 运行这段代码会报如下错误

  

Caused by: net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InaccessibleObjectException-- Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @182decdb

 

  

 

  网上查找是Java兼容性错误,在VM Option里面加上“--add-opens java.base/java.lang=ALL-UNNAMED” 可以解决。 如果直接用Java8 也不会出现这个错误。

  动态代理这块的内容比较基础,关键是要尝试在实际的项目中用到它,理解它的思想,然后实际应用上去就比较好了。 这周内容比较简单,坚持学习,加油!

  以上就是Java动态代理(java动态代理的实现方式)的详细内容,想要了解更多 Java动态代理的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: