为其他对象提供一种代理以控制对这个对象的访问。
代理模式和适配器模式很像,适配器模式把A接口转换成B接口
public class BAdapter implements B{
private A a;
public Badapter(A a) {
this.a = a;
}
public void b() {
a.toString();
}
}
而代理模式不是把A接口转换成B接口,而是把A接口转换成A接口:
public class AProxy implements A{
private A a;
public Badapter(A a) {
this.a = a;
}
public void b() {
a.toString();
}
}
那这代理模式有啥用,不和直接调用A一样的嘛?
但是可以在调用的方法前后加上一些逻辑判断,或者权限校验,甚至日志记录,那作用不就体现出来了吗。
public void b() {
if (getAuth()) {
this.a.a();
} else {
throw new BussinessException("");
}
}
静态代理
为每一个类去写一个代理类,这样太繁琐了,所以有了动态代理
动态代理
JDK动态代理
jdk动态代理只可以对接口进行代理,原因在后面解释:
定义接口
public interface Service {
public void doSave();
}
实现类
public class HelloService implements Service{
@Override
public void doSave() {
System.out.println("执行保存方法");
}
}
jdk动态代理要实现java.lang.reflect.InvocationHandler接口:
public class JdkProxy implements InvocationHandler {
private Service target;
public JdkProxy(Service target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long start = System.currentTimeMillis();
System.out.println("调用方法" + method.getName() + "开始");
Object o = method.invoke(target, args);
System.out.println("调用方法:" + method.getName() + ",参数:" + args + " 耗时 :"
+ (System.currentTimeMillis() - start) + "ms");
return o;
}
}
测试
public class Test {
public static void main(String[] args) {
Service s = new HelloService();
JdkProxy p = new JdkProxy(s);
Service s2 = (Service)Proxy.newProxyInstance(Service.class.getClassLoader(), new Class<?>[]{Service.class}, p);
s2.doSave();
}
}
为什么说jdk动态代理只能代理接口呢?
查看源码Proxy.newProxyInstance(ClassLoader arg, Class<?>[] arg0, InvocationHandler arg1)方法
//JDK 创建动态代理
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
......
// 重点
final Class<?>[] intfs = interfaces.clone();
......
// 生成增强之后的动态代理 Class
Class<?> cl = getProxyClass0(loader, intfs);
// 创建增强之后的动态代理 Class 实例对象
try {
......
final Constructor<?> cons = cl.getConstructor(constructorParams);
......
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
......
}
}
进入 Class<?> cl = getProxyClass0(loader, intfs); 方法
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// proxyClassCache 是 Proxy 的静态变量,是 WeakCache 类,
// 本质调用的 ProxyClassFactory 的 apply 方法
return proxyClassCache.get(loader, interfaces);
}
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 所有代理类的前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 一个用来生成唯一类名的数字
private static final AtomicLong nextUniqueNumber = new AtomicLong();
// 重点,这个方法被上面的 proxyClassCache.get 调用,也就是被 WeakCache 的 get 调用
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
...... // 一堆对接口的校验逻辑,省略
String proxyPkg = null; // 代理类包名
int accessFlags = Modifier.PUBLIC | Modifier.FINAL; // flag
......
long num = nextUniqueNumber.getAndIncrement(); // 唯一类名
// 拼接的唯一全限定代理类名
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//重点!!!这里生成了增强的代理类字节码文件
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 调用 native 方法加载代理类字节码到内存
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
......
}
}
}
java自动生成了一个 P r o x y 0 代 理 类 , 已 经 继 承 于 Proxy0代理类,已经继承于 Proxy0代理类,已经继承于Proxy0了,那就没办法继承其它类了
CGLIB动态代理
是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
我们要实现MethodInterceptor接口,调用Enhancer类进行配置,生成最后的代理对象
public class CglibProxy<T> implements MethodInterceptor {
private T target;
public CglibProxy(T target) {
this.target = target;
}
// 创建代理对象
public Object getProxyInstance() {
// 1.cglib工具类
Enhancer en = new Enhancer();
// 2.设置父类
en.setSuperclass(this.target.getClass());
// 3.设置回调函数
en.setCallback(this);
return en.create();
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("调用方法" + arg1.getName() + "开始");
Object result = arg1.invoke(target, arg2);
System.out.println("调用方法:" + arg1.getName() + ",参数:" + arg2 + " 耗时 :"
+ (System.currentTimeMillis() - start) + "ms");
return result;
}
}