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必须实现至少一个接口,否则不能进行代理。具体步骤也总结如下
- 实现InvocationHandler接口,将我们具体的增强逻辑代码写在invoke()方法中
- 使用Proxy类的newProxyInstance()方法去创建一个代理类的实例对象.
- 使用这个代理类对象
4.CGLIB代理
具体不展开讲了,jdk动态代理需要被代理类实现接口,如果被代理类没有实现接口,那么这么实现动态代理?这时候就需要用到CGLib了。这种代理方式就叫做CGlib代理。Cglib代理也叫作子类代理,他是通过在内存中构建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,然后加入自己需要的操作。因为使用的是继承的方式,所以不能代理final 类。
1206

被折叠的 条评论
为什么被折叠?



