1. 简介
代理模式就是为其他对象提供一种代理以控制对被代理对象的访问,也就是我们常说的中介;指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。
在现实生活中,这种情形非常的常见,比如请一个律师代理来打官司。
2. 静态代理
2.1 创建boss接口
package aaa;
public interface Boss {
void visit();
}
2.2 创建boss接口实现类真实类
package aaa;
public class RealBoss implements Boss {
private String name = "hello,boss";
@Override
public void visit() {
System.out.println(name);
}
}
2.3 创建Boss接口实现类秘书类
package aaa;
public class MiShu implements Boss {
private Boss subject;
public MiShu(Boss subject) {
this.subject = subject;
}
@Override
public void visit() {
subject.visit();
}
}
2.4 测试
package aaa;
public class Test01 {
public static void main(String[] args) {
MiShu subject = new MiShu(new RealBoss());
subject.visit();
}
}
2.5 小结
通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。
缺点:
但是也有缺点,每一个代理类都必须实现一遍委托类(比如Boss)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。
3. 动态代理
动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射
来实现的,借助Java自带的java.lang.reflect.Proxy
,通过固定的规则生成。
3.1 创建boss接口
package aaa;
public interface Boss {
void visit();
}
3.2 创建boss接口实现类真实类
package aaa;
public class RealBoss implements Boss {
private String name = "hello,boss";
@Override
public void visit() {
System.out.println(name);
}
}
这两步和前面静态代理差不多
3.3 创建boss代理类
package aaa;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class BossProxy implements InvocationHandler {
private Object object;
public BossProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(object, args);
return result;
}
}
3.4 测试
package aaa;
import java.lang.reflect.Proxy;
/**
* @version V1.0.0
* @author: WangQingLong
* @date: 2021/4/27 20:56
* @description:
*/
public class Test01 {
public static void main(String[] args) {
Boss realBoss = new RealBoss();
BossProxy proxy = new BossProxy(realBoss);
ClassLoader classLoader = realBoss.getClass().getClassLoader();
Boss boss = (Boss) Proxy.newProxyInstance(classLoader, new Class[]{Boss.class}, proxy);
boss.visit();
}
}
创建动态代理的对象,需要借助Proxy.newProxyInstance。该方法的三个参数分别是:
- ClassLoader loader表示当前使用到的appClassloader。
- Class<?>[] interfaces表示目标对象实现的一组接口。
- InvocationHandler h表示当前的InvocationHandler实现实例对象。
3.5 小结
用了动态代理我们把所有代理需要实现的行为集中到了invoke这一个方法去执行,不要再写大量模板代码了,并且我们实际上可以在一个InvocationHandler代理多个接口
缺点:
如果InvocationHandler中代理了两个接口,两个接口中有完全一模一样的两个方法,就没法去区分了
代理必须基于接口
,没有实现接口的类没法被代理
4. Cglib
Cglib 基于 ASM 框架操作字节码帮我们生成需要的代理对象,并且不要求实现接口,但是需要添加依赖
比静态代理和动态代理,Cglib代理可谓是备受推崇,首先它不用向静态代理和动态代理那样实现接口,其次它更方便了为我们提供了拦截器的一些接口,是我们能够更好的对一些方法的控制。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
public class UserDao {
public void doField(){
System.out.println("开始学习Cglib代理------------------------");
}
public void eat(){
System.out.println("吃吃吃吃吃-------------------");
}
public void pay(){
System.out.println("买买买买买-------------------");
}
}
代理的类,需要继承MethodIntercepeor,然后实现接口里为我们提供的唯一的一个方法intercept在这里我们可以通过Method.invoke()方法达到调用目标类,这里不用像jdk动态代理那样需要绑定接口
public class ProxyFactory implements MethodInterceptor {
private Object object;
public ProxyFactory(Object object) {
this.object = object;
}
public Object getProxyInstance() {
Enhancer en = new Enhancer();
en.setSuperclass(object.getClass());
en.setCallback(this);
return en.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("我开始工作了");
Object returnValue = method.invoke(object, objects);
System.out.println("我结束工作了");
return returnValue;
}
}
测试:
public class Client {
public static void main(String args[]){
UserDao proxy = (UserDao) new ProxyFactory(new UserDao()).getProxyInstance();
proxy.doField();
}
}