Java动态代理的理解

1.什么是动态代理

         在去深入理解动态代理之前,先来看看它的基本概念,简单来说,动态代理就是在程序运行期,创建目标对象的代理对象,对目标对象中的方法进行功能性增强的一种技术。可以看到,概念种出现了这么几种角色:①.真实角色,②.代理角色,③.方法,④.客户(访问角色)。那么访问角色本可以直接访问真实角色的某个方法,为什么在开发的过程种需要一个代理角色呢?也就说动态代理解决了什么问题。在这里我们明确一个核心概念:动态代理能够让真实对象专注于自己的核心功能,让代理对象拦截客户对真实对象的访问,另外可以在不修改方法源码的情况下,增强被代理对象的方法的功能。

        举个例子,小明(真实角色)的主要业务是唱歌,在还没火的时候自己跑东跑西去街头、酒吧等地方唱歌,在这期间需要自己负责找合适的场地,以及和酒吧老板谈工资等业务,突然有一天他火了,很多人要请他唱歌,所有的事亲历亲为他根本忙不过来,这个时候经纪人(代理角色)出现了,客户们要请小明唱歌,不能直接找到小明了,而是需要和经纪人谈,经纪人在商业等方面的理解比小明强(对代理对象的方法增强)。这样小明就可以专注于自己的唱歌业务了,经纪人的存在就是拦截了客户对小明(真实对象)的访问。

        相信通过上面这个例子,大家能够理解动态代理了。我们在做项目的时候把日志和异常统一处理就是利用了动态代理,让我们能够关注核心业务。

2.动态代理的常用方式

        动态代理的实现方式有两种,第一种是jdk自带的动态代理功能(基于接口的动态代理),它的实现前提是现有类必须拥有一个接口,因为它是通过对现有类接口的实现来完成的。第二种方式是cglib(基于类的动态代理),这是一个开源工具包,它的实现是通过继承现有类,然后重写现有类的方法实现的。

        我们以上述小明故事的场景,代理对象代理了小明的谈演出费的方法,看看具体怎么实现

3.JDK动态代理

        我们需要一个代理对象,而对象是类的具象化,所以我们需要一个代理类。在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。

       (1)首先定义一个接口,这个接口是一个公共接口,这个接口有一个talk()方法

public interface Person {
    //谈薪
    public void talk();
}

        (2)创建真实对象,实现上述接口,那么代理对象需要代理的就是这个接口

public class XiaoMing implements Person{
    @Override
    public void talk(){
        System.out.println("小明成功收取唱歌费");
    }
}

        (3)创建BrokerInvocationHandler类,这个类实现了InvocationHandler接口,我们通过这个类来动态生成代理类,InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。然后通过反射在invoke方法中执行代理类的方法。在代理过程中,在执行代理类的方法前或者后可以执行自己的操作,这就是spring aop的主要原理。

//用这个类自动生成代理类(这个并不是代理类,我们通过这个生成代理类)
public class BrokerInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Person person;

    public void setPerson(Person person) {
        this.person = person;
    }
    //生成得到代理类 固定的代码
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),person.getClass().getInterfaces(),
                this);
    }
    /**
     *处理代理实例并返回结果
     * @param proxy:代表动态代理对象
     * @param method:代表正在执行的方法
     * @param args:代表调用目标方法时传入的实参
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //代理过程中插入其他操作 对方法的增强
        System.out.println("客户和经纪人交流");
        //动态代理本质就是使用反射机制!!如下
        Object result = method.invoke(person,args);
        return result;
    }
}

        (4)创建客户对象,通过BrokerInvocationHandler生成代理对象,客户通过访问代理对象实现谈薪

public class Client{
    public static void main(String[] args) {
        //真实角色
        XiaoMing xiaoming = new XiaoMing();
        //代理角色:现在没有 先得到BrokerInvocationHandler对象
        BrokerInvocationHandler bid = new BrokerInvocationHandler();
        //通过调用程序处理角色来处理我们要调用的接口对象(知道我们要调用的是实现这个接口的哪个对象)
        bid.setPerson(xiaoming);
        //得到代理对象
        Person proxy = (Person) bid.getProxy();//这里的proxy是动态生成的,我们并未写!!
        proxy.talk();
    }
}

输出结果如下:

 可以看到,代理对象成功代理了小明的talk()方法;总结一下:jdk动态代理首先需要创建一个interface然后一个class实现这个interface,然后对这个class进行代理,这个class必须实现至少一个接口,否则不能进行代理。具体步骤也总结如下

  1. 实现InvocationHandler接口,将我们具体的增强逻辑代码写在invoke()方法中
  2. 使用Proxy类的newProxyInstance()方法去创建一个代理类的实例对象.
  3. 使用这个代理类对象

 4.CGLIB代理

        具体不展开讲了,jdk动态代理需要被代理类实现接口,如果被代理类没有实现接口,那么这么实现动态代理?这时候就需要用到CGLib了。这种代理方式就叫做CGlib代理。Cglib代理也叫作子类代理,他是通过在内存中构建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,然后加入自己需要的操作。因为使用的是继承的方式,所以不能代理final 类。
 

        

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李孛欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值