Java动态代理

3 篇文章 0 订阅

前言

代理是一种常用的设计模式,它为其他对象提供一种代理以控制对这个对象的访问。通俗来讲就是我们通过代理类来调用委托类的方法,并且我们可以在代理类中加入新的功能。它们之间的关系如下:
代理类与委托类的关系

静态代理

创建一个接口,用来约束委托类和代理类的方法。

public interface House {
    public void rent();
}

创建一个委托类(房东)

//委托类
public class Landlord implements House{
    @Override
    public void rent() {
        System.out.println("出租一间房子");
    }
}

创建一个代理类(中介)

//代理类
public class Intermediary implements House {
    House landlord;

    public Intermediary(House landlord) {
        this.landlord = landlord;
    }

    @Override
    //代理方法
    public void rent() {
//        调用委托类的方法并加上新的功能
        System.out.println("看房");
        landlord.rent();
    }
}

代理类引用了委托类,并且调用委托类的方法上可以增加新的功能。

测试

    @Test
    public void testStatic(){
        House landlord = new Landlord();
        House intermediary = new Intermediary(landlord);
        intermediary.rent();
    }

测试结果
静态代理的缺点很明显,如果委托类很多并且委托类有很多方法的话,我们都需要手动的为每一个类每一个方法创建代理,是十分麻烦的,由此引出动态代理,可以很好地解决静态代理的弊端。

动态代理

动态代理介绍

动态代理添加了一个中间处理类,当我们调用委托类的方法是,会进入中间处理类,我们可以将新添加的功能放在中间处理类。中间处理类可以对代理类中的函数进行统一管理,而不用像静态代理一样修改所有的代理方法。

动态代理主要有两种

  1. jdk动态代理 :委托类必须实现接口
  2. cglib动态代理 :通过继承的方式代理委托类,委托类没有接口也可以代理

jdk动态代理

jdk动态代理需要使用InvocationHandler接口和Proxy类的newProxyInstance方法。

创建一个接口

public interface UserService {
    public void addUser();
    public void deleteUser();
}

创建实现类(委托类)

public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

创建中间处理类

//实现InvocationHandler接口,成为中间处理类
public class UserServiceProxy implements InvocationHandler {
    private UserService service;

    public UserService getProxy(UserService service){
        this.service = service;
//        该方法返回一个代理对象
//        参数1位为类加载器,参数2为委托类的class类型接口数组,参数3为实现InvocationHandler的实现类
        return (UserService)Proxy.newProxyInstance(service.getClass().getClassLoader(),service.getClass().getInterfaces(),this);
    }

//    InvocationHandler的实现方法,被拦截的方法将在这里被调用
//    参数1为代理对象的实例,参数2为委托类被拦截的方法,参数3为方法的参数数组
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("权限检查...");
        Object invoke = method.invoke(service,args);

        return invoke;
    }
}

newProxyInstance方法会返回一个代理对象。

测试

  @Test
    public void testJdk(){
//        委托类
        UserService service = new UserServiceImpl();

//        中间处理类
        UserServiceProxy userServiceProxy = new UserServiceProxy();

//        代理类
        UserService serviceProxy = userServiceProxy.getProxy(service);

//        调用代理类方法
        serviceProxy.addUser();
        serviceProxy.deleteUser();
    }

测试结果
可以看到动态代理可以动态的管理委托类的所有方法。

cglib动态代理

使用cglib需要导入cglib的jar包。

cglib动态代理需要使用MethodInterceptor接口和Enhancer类。

创建委托类

public class Person {
    public void eat(){
        System.out.println("吃饭");
    }
}

创建中间处理类

//实现MethodInterceptor成为处理类
public class PersonProxy implements MethodInterceptor {

    public <T> T getProxy(Class<T> clazz){

        //创建工具类
        Enhancer enhancer = new Enhancer();

        //设置委托类为其父类
        enhancer.setSuperclass(clazz);

        //设置回调函数,即方法被拦截后调用的方法
        enhancer.setCallback(this);

        //创建Person的代理类并返回
        return (T) enhancer.create();
    }

    //该方法为回调方法,方法被拦截后将会调用
    //参数1为代理类对象,参数2为被拦截的委托类的方法,参数3为方法参数列表,参数4为被拦截的方法的代理对象
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("吃饭前要洗手");

        //参数1为代理类对象,参数2为方法参数列表
        Object invoke = methodProxy.invokeSuper(o,objects);
        return invoke;
    }
}

测试

    @Test
    public void testCglib(){
        //委托类
        Person p = new Person();

        //中间处理类
        PersonProxy personProxy = new PersonProxy();

        //代理类
        Person proxy = personProxy.getProxy(p.getClass());
        //调用代理类方法
        proxy.eat();

    }

测试结果
由于cglib是通过继承来实现代理,所以被final和static修饰的类或方法不能被代理,因为被static和final修饰的方法不能被重写,而被final修饰的类不能被继承,所以也就不能被代理了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值