目录
1. 静态代理
2. 动态代理
3. Cglib代理
代理模式:为一个对象提供一个替身,以控制对这个对象的访问。好处就是可以用来增强。
被代理的对象可以是 远程对象,创建开销大的对象 或者 需要安全控制的对象。
可以分为三类
- 静态代理
- 动态代理(JDK代理,接口代理)
- Cglib代理(属于动态代理,在内存动态的创建对象,而不需要实现接口)
示意图
1. 静态代理
目标对象与代理对象都要实现同一个接口或者继承相同父类。
代码实现:
public interface ITeacherDao {
String teach();
}
public class TeacherDao implements ITeacherDao{
private String name;
public TeacherDao(String name) {
this.name = name;
}
@Override
public String teach() {
System.out.println(name + "老师正在讲课。。。");
return name;
}
}
public class TeacherDaoProxy implements ITeacherDao{
private ITeacherDao teacherDao;
public TeacherDaoProxy(ITeacherDao teacherDao) {
this.teacherDao = teacherDao;
}
@Override
public String teach() {
System.out.println("开始静态代理。。。,可以进行增强");
String name = teacherDao.teach();
System.out.println("结束静态代理。。。");
return name;
}
}
Client:
public class Client {
public static void main(String[] args) {
ITeacherDao target = new TeacherDao("ksj");
TeacherDaoProxy proxy = new TeacherDaoProxy(target);
String teach = proxy.teach();
System.out.println(teach);
}
}
2. 动态代理
静态代理缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类 ,一旦接口增加方法,目标对象与代理对象都要维护。
这就要用到动态代理了,动态的在内存中构建代理对象,只需要目标对象实现接口。利用JDK的Api来实现。
java.lang.reflect.Proxy里面的
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
- ClassLoader loader:目标对象的类加载器。
- Class<?>[] interfaces: 目标对象实现的接口数组。
- InvocationHandler h:事件处理器,里面利用反射调用方法。
接口和目标类与上面静态代理相同,下面直接写代理工厂类
public class ProxyFactory {
private final Object target;
public ProxyFactory(Object target){
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理开始");
Object returnVal = method.invoke(target, args);
System.out.println("JDK代理结束");
return returnVal;
}
});
}
}
public class Client {
public static void main(String[] args) {
ITeacherDao target = new TeacherDao("ksj");
System.out.println("target=" + target.getClass());
ProxyFactory proxyFactory = new ProxyFactory(target);
ITeacherDao proxyInstance = (ITeacherDao) proxyFactory.getProxyInstance();
// proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
System.out.println("proxyInstance=" + proxyInstance.getClass());
String name = proxyInstance.teach();
System.out.println(name);
}
}
3. Cglib代理
Cglib
代理也叫作子类代理,属于动态代理。相比较静态代理和JDK代理,Cglib代理不需要实现接口。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接
口.
它广泛的被许多
AOP
的框架使用
,
例如
Spring AOP
,实现方法拦截。
- 目标对象需要实现接口,用JDK代理
- 目标对象不需要实现接口,用Cglib代理
简单来说就是实现MethodIterceptor接口,实现
intercept接口来实现代理。
代码实现:
public class TeacherDao {
public String teach() {
System.out.println(" 老师授课中 , 我是cglib代理,不需要实现接口 ");
return "hello";
}
}
public class ProxyFactory implements MethodInterceptor {
//维护一个目标对象
private Object target;
//构造器,传入一个被代理的对象
public ProxyFactory(Object target) {
this.target = target;
}
//返回一个代理对象: 是 target 对象的代理对象
public Object getProxyInstance() {
//1. 创建一个工具类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创建子类对象,即代理对象
return enhancer.create();
}
//重写 intercept 方法,会调用目标对象的方法
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
System.out.println("Cglib代理模式 ~~ 开始");
Object returnVal = method.invoke(target, args);
System.out.println("Cglib代理模式 ~~ 提交");
return returnVal;
}
}
public class Client {
public static void main(String[] args) {
//创建目标对象
TeacherDao target = new TeacherDao();
//获取到代理对象,并且将目标对象传递给代理对象
TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();
//执行代理对象的方法,触发intecept 方法,从而实现 对目标对象的调用
String res = proxyInstance.teach();
System.out.println("res=" + res);
}
}
还有其他代理变体:
- 防火墙代理
- 缓存代理
- 远程代理
- 同步代理等