关于Jar包的问题:Cglib 和JDK代理需要的相应的jar包
我用的maven管理的jar包,导入一个webmvc的依赖就可以了,没用maven的,网上找jar包吧,百度一大堆。pom文件导入依赖如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.2</version>
</dependency>
一.什么是代理?
代理是一种设计模式,即通过代理对象去操作目标对象,并且增加一些附加的业务功能。eg:在生活中,我们租房可以找房东,也可以找中介,房东就是目标对象,中介就是代理对象。中介可以联系到房东,可以执行房东的操作,还可以执行一些附加的操作,如收取中介费。即:代理对象具有比目标对象更加丰富的操作,因为代理对象中包含了目标对象,代理就是在目标对象的基础上扩展一些方法。实现了在不更改原有代码的情况下,实现功能的增加(加强)。
二.Java代理的分类
1.静态代理
1.1目标对象
//创建一个类实现Rent接口
public class Host implements Rent {
public void rent() {
System.out.println("房东准备租房");
}
}
1.2代理对象
代理类也实现了Rent接口(不实现也可以,关键是把目标对象host注入进去,扩展其功能),个人觉得实现同一接口在于表明代理对象和目标对象具有相同的功能(方法),更加直观。
//静态代理类,需要将代理的真实角色注入进来调用其方法,并且扩展一些方法
public class StaticProxy implements Rent{
//将目标对象注入进来
private Host host;
public void setHost(Host host) {
this.host = host;
}
public void rent() {
take();
host.rent();
}
private void take(){
System.out.println("带客户去看房");
}
}
结果:
带客户去看房
房东准备租房
1.3 局限性
代理对象是实际定义出来的类,是写死了的;如果需要被代理的类很多,那么是不是得创建很多的代理类呢 ?代码太多了,这是不合理的。
解决方式:
动态代理,在程序运行的时候,动态生成代理类。
2.动态代理
动态代理有:JDK动态代理、Cglib动态代理、其他。
2.1 JDK动态代理
(1)JDK动态代理的介绍
- 实现主要依赖于两个类:Proxy类、InvocationHandler接口。
- Proxy类,顾名思义,使用来创建代理类的。
- InvocationHandler接口,是调用处理程序接口,这个接口什么作用?调用处理,即代理对象调用目标对象方法的时候,会去执行该接口实现类的invoke方法,这个invoke方法就是真正执行目标对象方法和进行功能增强的地方。
- JDK动态代理是针对接口去代理的,即:可以代理实现了某一类接口的所有类。
- 只能代理实现了接口的类。否则,不能代理
(2)简单demo
(i)创建一个接口
//定义一个接口
public interface Pay {
public void pay();
}
(ii)创建目标对象去实现上面的接口,这样才能进行jdk动态代理
//目标对象,实现Pay接口
public class Weixin implements Pay {
@Override
public void pay() {
System.out.println("通过微信支付");
}
}
(iii)创建一个类实现InvocationHandler接口,对被调用的方法进行处理;顺便在里面定义一个方法,用来创建代理类对象。
//定义一个调用处理类,实现Invocationhandler接口,当代理对象调用目标对象的方法时,会执行调用处理类的invoke方法
public class PayProxy implements InvocationHandler {
//目标对象,需要被代理的对象
private Object target;
public void setTarget(Object target) {
this.target = target;
}
// 当代理类调用目标对象的方法时,会执行该方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//对目标对象方法的扩展部分,可自定义
System.out.println("执行了"+method.getName());
//执行目标对象的方法
method.invoke(target,args);
return null;
}
//生成代理类对象,不在本类定义也可以,纯个人习惯。
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
}
(iv)测试
public void TestJDkProxy(){
//目标对象
Weixin weixin=new Weixin();
//创建调用处理类的对象,并将目标对象注入进去,用来创建代理类对象,因为上文说过创建代理类对象的方法定义在调用处理类中。
PayProxy payProxy=new PayProxy();
payProxy.setTarget(weixin);
//得到代理类对象
Pay proxy = (Pay) payProxy.getProxy();
//调用方法
proxy.pay();
}
(v)结果
执行了pay
通过微信支付
(3)总结
JDK动态代理模式,只能代理那些实现了接口的类;Proxy创建实例的方法参数有:目标对象的类加载器、目标对象实现的接口、调用处理程序接口。
2.2 Cglib动态代理
Cglib和Jdk差别在于:
- JDK只能代理实现了接口的类,Cglib则是针对类的,不管实现接口与否,都可以代理。
- 依赖的相关类不一样,JDK是Proxy类、InvocationHandler接口;Cglib是Enhancer类和MethodInterceptor接口。
- 原理不一样:JDK通过在代理类中注入目标对象的引用(在代理类中定义一个目标对象类型的属性),然后扩展目标对象的方法;Cglib是生成目标对象的子类,覆盖其方法。前者是动态地在代理类中注入目标对象(如果将目标对象写死,就跟静态代理有点像了),后者是动态生成目标对象的子类。
- 适用场景:有接口选jdk,没接口选cglib
简单Demo:
(1)定义一个目标对象
//定义一个目标对象
public class Pay {
public void pay(){
System.out.println("通过支付宝支付");
}
}
(2)创建一个类实现MethodInterceptor接口,并在里面创建代理类对象。
public class CglibProxy implements MethodInterceptor {
//目标对象
private Pay pay;
public void setPay(Pay pay) {
this.pay = pay;
}
//代理对象调用方法时执行下面的方法
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//增强的部分
System.out.println("[Log]进入了"+method.getName()+"Cglib代理增强方法");
//调用目标对象中的方法
method.invoke(pay,args);
return null;
}
public Object getCglibProxy(){
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(pay.getClass());
//设置回调,去执行intercept方法
enhancer.setCallback(this);
//创建代理对象
Object proxy = enhancer.create();
return proxy;
}
}
(3)测试
[Log]进入了payCglib代理增强方法
通过支付宝支付
以上,Over。。