目录
1.静态代理
代理是一个基本的设计模式,代理通常充当着中间人的角色。只要逆向将额外的操作,从实际对象中分离到不同的地方的时候,特别是当你希望很容易的做出修改,从没有额外的操作转为使用这些操作的时候。就用代理。
先来看一个简单的代理
先来一个接口
public interface Interface {
void doSomething();
void somethingElse(String arg);
}
再来一个实现类:
public class RealObject implements Interface {
@Override
public void doSomething() {
System.out.println("doSomething");
}
@Override
public void somethingElse(String arg) {
System.out.println("somethingElse" + arg);
}
}
接下来用一个代理类来执行它:
public class SimpleProxy implements Interface {
private Interface proxied;
public SimpleProxy(Interface proxied) {
this.proxied = proxied;
}
@Override
public void doSomething() {
proxied.doSomething();
System.out.println("SimpleProxy doSomething");
}
@Override
public void somethingElse(String arg) {
proxied.somethingElse(arg);
System.out.println("SimpleProxy " + arg);
}
}
测试:
public class SimpleProxyDemo {
public static void consumer(Interface anInterface){
anInterface.doSomething();
anInterface.somethingElse("boom");
}
public static void main(String[] args) {
//consumer(new RealObject());
consumer(new SimpleProxy(new RealObject()));
}
}
结果:
ok,上面是静态代理,缺点是 如果目标类有一百个方法,那么代理类也会有一百个方法,这个样子逻辑会重复很多。 重点是动态代理,因为他能动态的创建代理,并且动态的处理对所代理的方法进行调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上。
2.JDK动态代理
动态代理的实现也分为两类,一类是基于接口的动态代理,一个是基于继承的动态代理,实现的代表就是基于Jdk的动态代理和基于CGLib的动态代理,
JDK动态代理实现要点:
接口和实现类还是和上面的一样
public class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
/**
* 所又通过动态代理实现的方法,全部使用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("prox:" + proxy.getClass() + ",method:" + method + ",args:" + args);
if (args != null) {
for (Object arg : args) {
System.out.println(" " + arg);
}
}
return method.invoke(proxied, args);
}
}
public class SimpleDynamicProxy {
public static void consumer(Interface anInterface) {
anInterface.doSomething();
anInterface.somethingElse("boom");
}
public static void main(String[] args) {
//正常业务调用
RealObject realObject = new RealObject();
consumer(realObject);
//现在擦汗如一个代理的调用链
Interface interfaces = (Interface) Proxy.newProxyInstance(
Interface.class.getClassLoader(),
realObject.getClass().getInterfaces(),
new DynamicProxyHandler(realObject)
);
consumer(interfaces);
}
}
通过调用静态方法的Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器,通常可以从已经被加载的对象中获得类加载器,还需要一个希望该代理实现的接口列表(不是类或者抽象类),以及InvocationHandler接口的一个实现。动态代理会将所有的调用重定向到调用处理器,因此通常会向调用处理器的构造器传递一个实际对象的引用。从而可以使的掉欧阳那个处理器在执行其中介任务时,可以将请求转发。
可以通过传递其他的参数来过滤某些方法的调用:
接口新增一个插入的方法:
当接口新增加方法后,静态代理的话代理类也要实现相应的接口,而动态代理的代理类什么都不用变。
public class MethodSelector implements InvocationHandler {
private Object object = null;
MethodSelector(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("insert"))
System.out.println("代理正在执行插入的方法");
return method.invoke(object, args);
}
}
public class SelectMethods {
public static void main(String[] args) {
RealObject realObject = new RealObject();
Interface anInterface = (Interface) Proxy.newProxyInstance(realObject.getClass().getClassLoader(),
realObject.getClass().getInterfaces(),
new MethodSelector(realObject)
);
anInterface.doSomething();
anInterface.insert("user");
anInterface.somethingElse("boom");
}
}
结果:
jdk源码解析:
本质上也就是JDK在运行的时候生成代理的类,java.lang.reflect.Proxy接收多少个接口就会生成多少个代理的类。每个代理的类和静态代理类一样实现了接口的所有的方法。动态生成的代理类属于中间变量的感觉,那我们来看看这个中间的变量示什么样子。
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", true);
3.CGLib的方式实现动态代理
CGLib是基于继承来实现动态代理的。
包依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
实现接口:
package com.wx.test1;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* User: Mr.Wang
* Date: 2020/1/27
*/
public class DynamicCGLibHandler implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before");
Object re = methodProxy.invokeSuper(o, objects);
System.out.println("after");
return re;
}
}
客户端调用:
public class Test2 {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealObject.class);
enhancer.setCallback(new DynamicCGLibHandler());
Interface anInterface = (Interface) enhancer.create();
anInterface.doSomething();
}
}
结果:
4.JDK动态代理和CGLib动态代理的区别
练习,使用动态代理实现一个事务管理:
https://blog.csdn.net/qq_41116058/article/details/81942396
https://www.cnblogs.com/caiyao/p/4783417.html