目录
1、静态代理(装饰器模式)
2、jdk动态代理
3、cjlib动态代理
概述:代理模式分为静态代理和动态代理,其中动态代理又包括jdk动态代理和cjlib动态代理,Spring框架底层用到了很多动态代理。
本质:使用代理对象增强被代理对象的方法。增强的意思就是在原有方法前后执行一些其他自定义的方法。
案例:Spring AOP、拦截器
既然叫代理,代理对象与被代理对象具有相同的行为功能。所以一般情况下,静态代理中代理对象和被代理对象都属同一接口。之所以叫静态代理,不是“随类的加载而加载”的意思,而是“固定的”,是因为一类对象都对应一个代理对象,这种创建代理对象的方法太过麻烦,总要创建各种类,可不可以仅写一个类就可以创建任意代理对象?使用动态代理实现。下面先列举静态代理demo
接口定义行为功能
package com.demo.statics;
public interface Man {
void speak();
}
被代理类
package com.demo.statics;
/**
* 被代理类
*/
public class BaoQiang implements Man {
@Override
public void speak() {
System.out.println("我是宝强");
}
}
代理类
package com.demo.statics;
/**
* 代理类
*/
public class Songjie implements Man {
private Man man;
public Songjie(Man man) {
this.man = man;
}
@Override
public void speak() {
System.out.println("我是宋jie代理");
man.speak();
}
}
测试
package com.demo.statics;
public class MainTest {
public static void main(String[] args) {
Songjie proxy = new Songjie(new BaoQiang());
proxy.speak();
}
}
运行结果
动态代理对象的类型与常规类不一样,类似下面这种
jdk动态代理的被代理类必须要实现接口,$Proxy0能与实现接口相互转换,如果没实现接口会类型转异常。如果被代理类实现多个接口,那么$Proxy0可以与任意接口相互转换。
demo
接口定义行为功能
package com.demo.dynamic;
public interface God {
String fly();
}
package com.demo.dynamic;
public interface Man {
String speak();
}
被代理类
package com.demo.dynamic;
/**
* 被代理类
*/
public class BaoQiang implements Man, God {
@Override
public String speak() {
return "我是宝强";
}
@Override
public String fly() {
return "我会飞";
}
}
使用jdk底层api创建代理对象
package com.demo.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler {
private Object target;
public JdkProxy(Object target) {
this.target = target;
}
public static T createProxy(T t) {
/**
* ClassLoader loader 被代理类的类加载器
* Class>[] interfaces 被代理类实现的所有接口
* InvocationHandler h 执行处理器,调用目标方法时,会被InvocationHandler拦截
*/
Object o = Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new JdkProxy(t));
return (T) o;
}
/**
* 代理对象执行目标方法时都会被InvocationHandler拦截,执行invoke方法
*
* @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 invoke = method.invoke(target, args);
return "返回值:" + invoke;
}
}
测试类
package com.demo.dynamic;
public class MainTest {
public static void main(String[] args) {
Man proxy = JdkProxy.createProxy(new BaoQiang());
System.out.println(proxy.speak());
System.out.println(((God) proxy).fly());
}
}
运行结果
上述jdk动态代理的实现必须给被代理类实现接口,如果我不想实现接口也具有代理功能,就可以使用cjlib动态代理。它是根据cjlib包中api创建代理对象的,要先引入包然后使用增求器Enhancer来创建代理对象。
demo
被代理类
package com.demo.cjlib;
/**
* 被代理类
*/
public class BaoQiang {
public String speak() {
return "我是宝强";
}
}
使用cjlib底层api创建代理对象
package com.demo.cjlib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CjlibProxy {
public static T createProxy(T t) {
// 1、创建增强器
Enhancer enhancer = new Enhancer();
// 2、设置父类,使代理类具有父类的方法
enhancer.setSuperclass(t.getClass());
// 3、设置回调,当代理对象调用方法时,会被回调拦截
enhancer.setCallback(new MethodInterceptor() {
/**
* 拦截方法,当代理对象调用方法时,会被回调拦截
* @param o 代理对象
* @param method 被代理对象方法元信息
* @param objects 方法参数
* @param methodProxy 代理对象方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cjlib增强方法---");
Object o1 = methodProxy.invokeSuper(o, objects);
return "返回值:" + o1;
}
});
Object o = enhancer.create();
return (T) o;
}
}
测试类
package com.demo.cjlib;
public class MainTest {
public static void main(String[] args) {
BaoQiang proxy = CjlibProxy.createProxy(new BaoQiang());
System.out.println(proxy.speak());
}
}
运行结果