代理模式-动态代理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gfd54gd5f46/article/details/78111397

动态代理实现:


  • jdk动态代理

  • cglib动态代理


注意:动态代理中,代理类并不是在Java代码中实现,而是在运行时期生成



JDK动态代理


  • 利用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口定义代理类的实现。

创建抽象的委托者


  • UserService.java
/**
 * 委托类和代理类的接口
 * @author LingDu
 */
public interface UserService {
    public void insert();
}

具体的委托者


  • UserServiceImp.java
/**
 * 委托类
 * @author LingDu
 */
public class UserServiceImp implements UserService {

    @Override
    public void insert() {
        System.out.println("insert success");
    }
}

具体的代理者


  • MyInvocatioHandler.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 利用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口定义代理类的实现。
 * @author LingDu
 */
public class MyInvocatioHandler implements InvocationHandler {

    private Object obj;

    public MyInvocatioHandler(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("begin...");
        Object result = method.invoke(obj, args);
        System.out.println("end...");
        return result;//返回代理对象
    }

    //生成代理对象
    public Object getProxyObj() {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class<?>[] interfaces = obj.getClass().getInterfaces();
        return Proxy.newProxyInstance(loader, interfaces, this);
    }
}

  • 代理类实现InvocationHandler接口重写invoke(Object proxy, Method method, Object[] args)方法

  • 创建代理对象实例必须使用Proxy类中的newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )方法


newProxyInstance完整的写法如下:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )



注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为:

  • ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的

  • Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型

  • InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入



测试

UserService userServiceProxy = (UserService) new MyInvocatioHandler(new UserServiceImp()).getProxyObj();
userServiceProxy.insert();

1


JDK动态代理总结


      使用内置的Proxy实现动态代理有一个问题:被代理的类必须实现接口,未实现接口则没办法完成动态代理。如果项目中有些类没有实现接口,则不应该为了实现动态代理而刻意去抽出一些没有实例意义的接口,通过cglib可以解决该问题。



cglib动态代理


Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展


  • Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)

  • Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.


引入cglib所需的jar包

<!-- https://mvnrepository.com/artifact/cglib/cglib-nodep -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib-nodep</artifactId>
    <version>3.1</version>
</dependency>
  • 如果去Maven资源库下载的话注意一定要下载:cglib-nodep 的版本才可以用

2


创建抽象的委托者


  • UserService.java
/**
 * 委托类和代理类的接口
 * @author LingDu
 */
public interface UserService {
    public void insert();
}

具体的委托者


  • UserServiceImp.java
/**
 * 委托类
 * @author LingDu
 */
public class UserServiceImp implements UserService {

    @Override
    public void insert() {
        System.out.println("insert success");
    }
}

创建代理者


  • CglibProxy.java
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 实现MethodInterceptor接口重写intercept()方法
 * @author LingDu
 */
public class CglibProxy implements MethodInterceptor {
    private Object target;

    public CglibProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("begin...");
        Object result = methodProxy.invoke(target, args);
        System.out.println("end...");
        return result;// 返回代理对象
    }

    public Object getProxyObj(){
        //增强器,动态代码生成器
        Enhancer enhancer = new Enhancer();
        //回调方法
        enhancer.setCallback(this);
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //返回对象
        return enhancer.create();
    }

}

测试

UserService userService  = (UserService) new CglibProxy(new UserServiceImp()).getProxyObj();
userService.insert();

3


注意:使用cglib可以实现动态代理,即使被代理的类没有实现接口,但被代理的类必须不是final类。


延伸

在Spring的AOP编程中:

  • 如果加入容器的目标对象有实现接口,用JDK代理

  • 如果目标对象没有实现接口,用Cglib代理


猜你喜欢

转载自blog.csdn.net/gfd54gd5f46/article/details/78111397
今日推荐