利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象),代理的是接口(Interfaces),不是类(Class),也不是抽象类。在运行时才知道具体的实现,spring aop就是此原理。
通常使用场景有:
1、代理常用的接口的实现类(即在单机架构中,接口实现服务,在这种场景中想spring容器中注册的bean是接口的实现类)
在spring中主要处理业务思路的两种方式,
2、第二种场景是,通过代理实现一个接口的的stub的代理根对象,是由代理的handler 进行业务处理,不存在接口的具体实现类
常见的使用场景有:1、有远程调用dubbo服务,通过stub实现mybtis的mapper操作,等类似的场景
一、通过动态代理的原理,使需要进行切面处理的业务。通过代理技术将需要切入的业务前置处理器,或者后置处理器
如:1、对平台运行过程中的请求,进行统一的参数验证,2、通过注解的形式将事务机制切入到某些的业务中,
主要思想是:1、对需要进行业务处理的接口统一实现一个代理对象(proxy)(cglib框架技术)在代理对象中实现需要切入的业务业务,2、以及或者在某些条件下再调用被代理接口所要处理实现类的业务
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException
newProxyInstance,方法有三个参数:
loader: 用哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接口
h:动态代理方法在执行时,会调用h里面的invoke方法去执行
定义一个接口
package com.xhx.java;
/**
* xuhaixing
* 2018/7/30 21:32
**/
public interface IVehical {
void run();
}
要扩展的类:
package com.xhx.java;
/**
* xuhaixing
* 2018/7/30 21:33
**/
public class Car implements IVehical {
public void run() {
System.out.println("Car会跑");
}
}
调用处理类invocationhandler
package com.xhx.java;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* xuhaixing
* 2018/7/30 21:38
**/
public class VehicalInvacationHandler implements InvocationHandler {
private final IVehical vehical;
public VehicalInvacationHandler(IVehical vehical){
this.vehical = vehical;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("---------before-------");
Object invoke = method.invoke(vehical, args);
System.out.println("---------after-------");
return invoke;
}
}
invoke三个参数:
proxy:就是代理对象,newProxyInstance方法的返回对象
method:调用的方法
args: 方法中的参数
package com.xhx.java;
import java.lang.reflect.Proxy;
/**
* xuhaixing
* 2018/7/30 21:30
**/
public class App {
public static void main(String[] args) {
IVehical car = new Car();
IVehical vehical = (IVehical)Proxy.newProxyInstance(car.getClass().getClassLoader(), Car.class.getInterfaces(), new VehicalInvacationHandler(car));
vehical.run();
}
}
上面代码中,代理car对象,调用run方法时,自动执行invocationhandler中的invoke方法。
上述的代理:是将接口的实现类的业务进行代理处理的机制,再spring中常见的案例是,service的实现的impl,再注册到spring容器中bean的实现还是impl实现
2、动态代理技术实现的第二种思路是,对接口实现一个代理类的stub(根),再通过代理的业务梳理InvocationHandler实现业务处理(再抽象层面理解,其处理的业务都是一致性的,只是参数数不同,最终做的操作不同),例如,http请求协议,都是通过网络请求获取(远程)数据,不同的是数据的来源不同,2、再Java中,使用mybatis框架获取数据的时候,我们定义了大量的mapper。其实他的思路是通过代理的方式对于mapper各个接口实例化一个代理对象(stub),再通过InvocationHandler代理的处理机制,通过代理不同的接口以及不同的参数,统一从一个数据源中获取不同的数据
示例:
代理处理的接口:
import java.lang.reflect.Method;
/**
* @author wangyong
* @date 2017.10.14
*/
public interface HTTPHandler {
void handle(Method method,Object [] args);
}
代理需要实现的业务
import java.lang.reflect.Method;
/**
* @author 李佳明
* @date 2017.10.14
*/
public class ProxyHandlerDemo implements HTTPHandler {
@Override
public void handle(Method method,Object [] args) {
System.out.println("处理业务方法Method:{"+method.getName()+"}");
System.out.println("业务处理参数:");
if (null != args && args.length>0){
for (Object arg:args){
System.out.print(arg.getClass()+":\t");
System.out.println(arg);
}
}
}
}
实例化:代理对象
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
public Object createProxy(String className){
try {
Class<?> target = Class.forName(className);
InvocationHandler invocationHandler = createInvocationHandler();
Object proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{target}, invocationHandler);
return proxy;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* 创建InvocationHandler,将方法调用全部代理给DemoHttpHandler
*
* @return
*/
private InvocationHandler createInvocationHandler() {
return new InvocationHandler() {
private ProxyHandlerDemo demoHttpHandler = new ProxyHandlerDemo();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
demoHttpHandler.handle(method,args);
return null;
}
};
}
}
被代理处理的接口:
public interface TargetInterface {
public void method1();
public String method2(String name);
public int method3(Integer x);
}
测试类
public class TestMain {
public static void main(String[] args) {
ProxyUtil proxyUtil = new ProxyUtil();
TargetInterface targetInterface = (TargetInterface) proxyUtil.createProxy("com.wangyong.learnproject.proxy.TargetInterface");
targetInterface.method2("汪勇");
}
}