searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Java 动态代理的简单实现

2023-08-01 10:08:14
10
0

一、代理的优势

代理通过继承或一些其它接口方法来实现原实现类额外的功能,而不修改实现类,可以避免额外功能代码对原代码的侵入。
假设有一个接口
public interface userservice { 
boolean login(String name,String passwd); 
boolean logout(); 
}
对接口的实现类为
public class userserviceimpl1 implements userservice {

    public boolean login(String name, String passwd) {
        System.out.println("----login-----");
        return false;
    }

    public boolean logout() {
        System.out.println("----logout-----");
        return false;
    }
}
如何在不修改实现类的情况下实现功能的增加。

二、代理的实现方式

(1)静态代理

public class staticproxy implements userservice{
    userserviceimpl1 l;
    staticproxy(userserviceimpl1 u)
    {l=u;}
    @Override
    public boolean login(String name, String passwd) {
        System.out.println("----before-----");
        boolean res=l.login(name,passwd);
        System.out.println("----after-----");
        return res;
    }

    @Override
    public boolean logout() {
        System.out.println("----before-----");
        boolean res=l.logout();
        System.out.println("----after-----");
        return false;
    }
}
通过新建一个类继承接口,同时设置一个实现类的对象属性,来完成方法的调用和额外功能的实现。如果有多个类需要代理,则需要创建多个代理类,代码冗余且容易出错。

(2)动态代理

通过JDK或CGlib两种工具来实现java动态字节码的加载。
  • JDK方式

通过
Proxy.newProxyInstance(ClassLoader,Interfaces,InvocationHandler)
来返回一个代理对象,可以强制类型转换为接口类型,之后使用接口方法,调用的是Handler中的方法,即自定义方法。前面参数传入的是实现类的类加载器和接口,之后自定义实InvocationHandler接口类。
public class userviceproxy implements InvocationHandler {
    Object object;
    userviceproxy(Object target)
    {
        object=target;
    }
    userviceproxy(){}
    public Object bind(Object target)
    {
        object=target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
        target.getClass().getInterfaces(),this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws 
    Throwable {
        System.out.println("----before-----");
        Object t=method.invoke(object,args);
        System.out.println("----after-----");
        return t;
    }
}
类加载器(ClassLoader)的作用:
  1. 将.java文件编译后得到的.class文件字节码加载进JVM方法区中。
  2. 通过类加载器创建类的Class对象,进而创建这个类的对象。

类加载器和这个类本身组成了类在JVM中的唯一性,即只有经过相同的类加载器加载的class文件类才是同一个类,否则即使来源于同一个class文件,在同一个JVM中使用,但由不同的classloader加载,那么也是不同的类。相同是指包括代表类的Class对象的equals()方法、 isAssignableFrom() 方法、 isInstance() 方法的返回结果。在加载class文件时,jvm会给类分配一个独特的classloader。动态代理中,不存在java文件和class文件,因此不需要classloader加载,但jvm中不存在代理类的class对象,需要一个classloader来创建class对象,此时借用被代理类的classloader来创建。

  • CGlib方式实现动态代理

UserService userService = new UserService();
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(TestCglib.class.getClassLoader());
        enhancer.setSuperclass(userService.getClass());

        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args,
             MethodProxy methodProxy) throws Throwable {
                System.out.println("--- cglib log ----");
                Object ret = method.invoke(userService, args); 
                // 执行原始方法
                return ret;
            }
        };
        enhancer.setCallback(interceptor);
        UserService userServiceProxy = (UserService) enhancer.create();
        userServiceProxy.login("zhenyu", "123456");
        userServiceProxy.register(new User());
 
 
三、总结
 
 
JDK
Cglib
classloader
enhancer.setClassLoader()
Interfaces
setSuperClass
InvocationHandler
methodIntercepter
Proxy.newProxyInstance() cast to interface
enhancer.create() cast to superclass
  • JDK通过实现接口来创建动态代理,要求原始类实现接口,只代理接口上的方法,方法返回也只能转换为接口类型proxy.newProxyInstance(classloader,interfaces,invocationhandler)。
  • CGlib通过继承原始类来创建动态代理,不需要原始类实现接口,方法返回转换为父类类型。
 

0条评论
作者已关闭评论
j****m
4文章数
0粉丝数
j****m
4 文章 | 0 粉丝
j****m
4文章数
0粉丝数
j****m
4 文章 | 0 粉丝
原创

Java 动态代理的简单实现

2023-08-01 10:08:14
10
0

一、代理的优势

代理通过继承或一些其它接口方法来实现原实现类额外的功能,而不修改实现类,可以避免额外功能代码对原代码的侵入。
假设有一个接口
public interface userservice { 
boolean login(String name,String passwd); 
boolean logout(); 
}
对接口的实现类为
public class userserviceimpl1 implements userservice {

    public boolean login(String name, String passwd) {
        System.out.println("----login-----");
        return false;
    }

    public boolean logout() {
        System.out.println("----logout-----");
        return false;
    }
}
如何在不修改实现类的情况下实现功能的增加。

二、代理的实现方式

(1)静态代理

public class staticproxy implements userservice{
    userserviceimpl1 l;
    staticproxy(userserviceimpl1 u)
    {l=u;}
    @Override
    public boolean login(String name, String passwd) {
        System.out.println("----before-----");
        boolean res=l.login(name,passwd);
        System.out.println("----after-----");
        return res;
    }

    @Override
    public boolean logout() {
        System.out.println("----before-----");
        boolean res=l.logout();
        System.out.println("----after-----");
        return false;
    }
}
通过新建一个类继承接口,同时设置一个实现类的对象属性,来完成方法的调用和额外功能的实现。如果有多个类需要代理,则需要创建多个代理类,代码冗余且容易出错。

(2)动态代理

通过JDK或CGlib两种工具来实现java动态字节码的加载。
  • JDK方式

通过
Proxy.newProxyInstance(ClassLoader,Interfaces,InvocationHandler)
来返回一个代理对象,可以强制类型转换为接口类型,之后使用接口方法,调用的是Handler中的方法,即自定义方法。前面参数传入的是实现类的类加载器和接口,之后自定义实InvocationHandler接口类。
public class userviceproxy implements InvocationHandler {
    Object object;
    userviceproxy(Object target)
    {
        object=target;
    }
    userviceproxy(){}
    public Object bind(Object target)
    {
        object=target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
        target.getClass().getInterfaces(),this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws 
    Throwable {
        System.out.println("----before-----");
        Object t=method.invoke(object,args);
        System.out.println("----after-----");
        return t;
    }
}
类加载器(ClassLoader)的作用:
  1. 将.java文件编译后得到的.class文件字节码加载进JVM方法区中。
  2. 通过类加载器创建类的Class对象,进而创建这个类的对象。

类加载器和这个类本身组成了类在JVM中的唯一性,即只有经过相同的类加载器加载的class文件类才是同一个类,否则即使来源于同一个class文件,在同一个JVM中使用,但由不同的classloader加载,那么也是不同的类。相同是指包括代表类的Class对象的equals()方法、 isAssignableFrom() 方法、 isInstance() 方法的返回结果。在加载class文件时,jvm会给类分配一个独特的classloader。动态代理中,不存在java文件和class文件,因此不需要classloader加载,但jvm中不存在代理类的class对象,需要一个classloader来创建class对象,此时借用被代理类的classloader来创建。

  • CGlib方式实现动态代理

UserService userService = new UserService();
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(TestCglib.class.getClassLoader());
        enhancer.setSuperclass(userService.getClass());

        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args,
             MethodProxy methodProxy) throws Throwable {
                System.out.println("--- cglib log ----");
                Object ret = method.invoke(userService, args); 
                // 执行原始方法
                return ret;
            }
        };
        enhancer.setCallback(interceptor);
        UserService userServiceProxy = (UserService) enhancer.create();
        userServiceProxy.login("zhenyu", "123456");
        userServiceProxy.register(new User());
 
 
三、总结
 
 
JDK
Cglib
classloader
enhancer.setClassLoader()
Interfaces
setSuperClass
InvocationHandler
methodIntercepter
Proxy.newProxyInstance() cast to interface
enhancer.create() cast to superclass
  • JDK通过实现接口来创建动态代理,要求原始类实现接口,只代理接口上的方法,方法返回也只能转换为接口类型proxy.newProxyInstance(classloader,interfaces,invocationhandler)。
  • CGlib通过继承原始类来创建动态代理,不需要原始类实现接口,方法返回转换为父类类型。
 

文章来自个人专栏
myjavatest
4 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0