一、代理模式
代理模式是为某一个对象(委托类)提供一个代理(代理类),用来控制对这个对象的访问。委托类和代理类有一个共同的父类或父接口,代理类会对请求做预处理、过滤,将请求分配给指定的对象。
生活中的常见代理有:租房中介、婚庆公司等。
代理类的两个设计原则:
- 代理类与委托类具有相似的行为
- 代理类增强委托类的行为
常用的代理模式:
二、静态代理
1.代理三要素 (以结婚为例)
- 有共同的行为(结婚)- 定义接口
- 目标角色/真实角色(新人)- 实现接口
- 代理角色(婚庆公司)- 实现接口 增强用户行为
2.代码
(1)有共同的行为(结婚)- 定义接口
public interface Marry {
void toMarry();
}
(2)目标角色/真实角色(新人)- 实现接口
public class You implements Marry{
@Override
public void toMarry() {
System.out.println("我结婚了");
}
}
(3)代理角色(婚庆公司)- 实现接口 增强用户行为
public class MarryProxy implements Marry{
private Marry target;
public MarryProxy(Marry target) {
this.target = target;
}
@Override
public void toMarry() {
before();
target.toMarry();
after();
}
private void after() {
System.out.println("百年好合");
}
private void before() {
System.out.println("婚礼现场布置中");
}
}
(4)测试
public static void main(String[] args) {
You you = new You();
MarryProxy marryProxy = new MarryProxy(you);
marryProxy.toMarry();
}
结果如下:

3.静态代理特点
- 目标角色固定
- 在应用程序之前就得知目标角色
- 代理对象会增强目标对象的行为
- 有可能存在多个代理,产生“类爆炸”
三、动态代理
可以根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象。
动态代理的两种实现方式:
动态代理的特点:
- 目标对象不固定
- 在程序运行时,动态创建目标对象
- 代理对象会增强目标对象的行为
四、JDK动态代理
1.实现过程
public class JdkHandler implements InvocationHandler {
private Object target;
public JdkHandler(Object target) {
this.target = target;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法执行前");
Object object = method.invoke(target, args);
System.out.println("方法执行后");
return object;
}
}
(1)定义一个动态代理类,该类去实现InvocationHandler
这个接口。
(2)在该类中定义一个方法,使用Proxy.newProxyInstance
得到代理对象,newProxyInstance
有三个参数,如下:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
-
ClassLoader loader
:该动态代理类的类加载器
-
Class<?>[] interfaces
:目标对象的接口数组
-
InvocationHandler h
:传入InvocationHandler 接口的实现类,在这里填入的是该动态代理类,因为该动态代理类去实现了InvocationHandler 这个接口。
(3)重写InvocationHandler
中的invoke
方法,调用目标对象的方法并且增强目标对 象的行为。invoke
方法同样有三个参数,如下:
public Object invoke(Object proxy, Method method, Object[] args)
-
Object proxy
:调用该方法的代理实例
-
Method method
:目标对象的方法
-
Object[] args
:目标对象的方法所需要的参数
(4)测试:
public static void main(String[] args) {
You you = new You();
JdkHandler jdkHandler = new JdkHandler(you);
Marry proxy = (Marry)jdkHandler.getProxy();
proxy.toMarry();
}
结果:

以上结果说明,当执行到proxy.toMarry()这行代码时,底层会自动去调用动态代理类JdkHandler
中的invoke
方法。
2.执行流程

五、CGLIB动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能使用JDK的动态代理。
cglib是针对类来实现代理的,它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
cglib动态的原理如下图:

可以看到,每次调用代理类的方法都会被拦截器所拦截,在拦截器中才是调用目标类的该方法的逻辑。
1.引入依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2.实现过程
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("方法执行前");
Object object = methodProxy.invoke(target, objects);
System.out.println("方法执行后");
return object;
}
}
(1)定义一个类去实现MethodInterceptor
接口,并且重写intercept
拦截器方法。
(2)在类中定义一个方法getProxy
,在方法中设置:让目标类成为该动态代理类的父类,并且设置回调对象为本身。最后通过create
方法返回生成的代理对象。
(3)在intercept
拦截器方法调用目标类的方法,并且增强行为目标类的行为或写上一些逻辑。
(4)测试:
public static void main(String[] args) {
You you = new You();
CglibProxy cglibProxy = new CglibProxy(you);
You proxy = (You) cglibProxy.getProxy();
proxy.toMarry();
}
结果:

以上结果说明,每次动态代理对象调用目标对象的方法时,都会被拦截器拦截,然后运行拦截器中的代码。
六、JDK代理和CGLIB代理的区别
- JDK动态代理实现接口,Cglib动态代理继承思想
- JDK动态代理(目标对象存在接口时)执行效率高于Cglib
- 如果目标对象有接口实现,选择JDK代理,如果没有接口实现选择Cglib代理