代理模式解析,静态代理和动态代理

简单理解:

我们在编写增删改查时,如果需要在不改变原有的类的结构的基础上,对这些数据库CRUD操作追加额外的日志记录功能。在项目研发中,通常使用的是spring框架中的aop设计模式或者拦截器。而他们的原理便是基于动态代理的思想。

代理模式是如何实现的?以日志记录为例子。

静态代理:

代理模式中有三个基本角色-----真实角色,抽象角色,代理角色。

抽象角色:增删改查的接口UserService

public interface UserService {

    void select();

    void save();

    void delete();

    void update();
}

真实角色:增删改查的实现类UserServiceImpl,实现了UserService接口

public class UserServiceImpl implements UserService {
    public void select() {
        System.out.println("查");
    }

    public void save() {
        System.out.println("增");
    }

    public void delete() {
        System.out.println("删");
    }

    public void update() {
        System.out.println("改");
    }
}

代理角色:同样实现接口的代理类UserProxy

public class UserProxy implements UserService {

    private UserService userService;

    //通过set方式注入真实对象
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void select() {
        System.out.println("这是查找");
        userService.select();
    }

    public void save() {
        System.out.println("这是增加");
        userService.save();
    }

    public void delete() {
        System.out.println("这是删除");
        userService.delete();
    }

    public void update() {
        System.out.println("这是修改");
        userService.update();
    }
}

测试类:

public class StaticProxy {
    @Test
    public void run(){
        //set方式注入真实角色UserServiceImpl
        UserProxy userProxy = new UserProxy();
        userProxy.setUserService(new UserServiceImpl());
        //通过代理角色实现真实角色的相关方法
        userProxy.select();
        userProxy.save();
        userProxy.update();
        userProxy.delete();
    }
}

 结果:

这是查找

这是增加

这是修改

这是删除

Process finished with exit code 0

由上可知,我们通过将代理类和真实的实现类实现相同的接口UserService,然后在代理类中注入了真实的实现类,通过操作代理类便可调用真实实现类的方法,实现了静态代理。

动态代理:

如果使用静态代理,每一个真实实现类都需要编写一个代理类,这在真实开发中是行不通,大大的降低了程序运行的效率。所以我们需要使用动态代理来取代静态代理,动态代理会根据真实实现类的类型自动去生成代理类对象,提高了效率。

常用的动态代理技术有Jdk动态代理和Cglib动态代理。下面主要讲解Jdk动态代理。

实现动态代理有实现接口和继承类两种方式,Jdk动态代理采用实现接口的方式。

首先需要熟悉InvocationHander接口和Proxy类。实现InvocationHander接口必须要实现invoke方法,而invoke方法在动态代理调用方法的时候被调用。简单来讲,invoke方法里面调用真实的业务逻辑和增强的业务逻辑。Proxy类中有静态方法newProxyInstance用来生成代理对象。

主要代码如下:

public class JdkDynamicProxy implements InvocationHandler {

    private Object object;

    //注入真实角色
    public void setUserService(Object object) {
        this.object = object;
    }

    //生成代理对象
    //newProxyInstance为Proxy类的静态方法,三个参数的含义:
    //第一个参数ClassLoader loader:类的加载器,传入我们自定义类的加载器
    //第二个参数Class<?>[] interfaces 注意很重要 这个参数是传入一个接口数组
    //第三个参数 h:类型是InvocationHandler,传入InvocationHandler接口的子类
    public Object getProxy(){
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }

   //proxy:代理类实例; method:被代理对象的方法;args:被代理对象的方法的参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //日志输出
        log(method.getName());
        //实现真实角色的方法
        method.invoke(object, args);   //用了反射的思想
        return null;
    }

    //代理对象的一些附加业务
    public void log(String msg){
        System.out.println("这是"+msg+"方法");
    }

}
测试类:
public class DynamicTest {

    @Test
    public void test(){
        UserService userService = new UserServiceImpl();
        //set方式注入真实角色
        JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy();
        jdkDynamicProxy.setUserService(userService);
        UserService proxy = (UserService)jdkDynamicProxy.getProxy();
        proxy.select();
    }
}

结果:

这是select方法

这是save方法

这是update方法

这是delete方法

Process finished with exit code 0

动态代理是aop的底层原理,mybatis框架中mapper层的映射也用到了动态代理。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值