代理模式,是很多框架中应用到的基础,例如mybatis中对于配置环境的元素的读取,以及推荐使用的mapper的接口,其中使用到的就是JDK动态代理技术,然而在spring中也有对应的体现,然而会产生疑问,仅提供一个接口,怎么会执行呢?其实代理的本质就是继承。
好了,我们慢慢的一点点解答:
JDK静态代理:
我们设计了一个HelloService接口和其对应的实现类HelloServiceImpl类:public interface HelloService {
public void sayHello(String name);
}
对应的实现类:
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello(String name) {
// TODO Auto-generated method stub
System.out.println("hello " + name);
}
}
如果我们先通过代理的方法来实现的话,我们首先要做的是构建一个代理类,代理类也需要实现HelloService接口:
public class JDKSTA implements HelloService {
private HelloServiceImpl helloServiceImpl;
public JDKSTA(HelloServiceImpl helloServiceImpl){
this.helloServiceImpl = helloServiceImpl;
}
@Override
public void sayHello(String name) {
System.out.println("我准备说hello了");
helloServiceImpl.sayHello(name);
System.out.println("我说过hello了");
}
}
对应的测试类:
public class JDKstatEST {
public static void main(String[] args) {
//创建JDK代理对象
HelloService proxy= new JDKSTA(new HelloServiceImpl());
proxy.sayHello("zhang san");
}
}
这样则完成了JDK的静态代理的过程。
JDK动态代理:
HelloService接口和其对应的实现类都不变,我们重新设计一个新的代理类,这次的代理类需要继承InvocationHandler接口,其他的说明在注释中体现了:
public class HelloServiceProxy implements InvocationHandler{
private Object target;
/**
* 帮绑定委托对象并方辉一个代理类
* @param target
* @return
*/
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
this);
}
@Override
/**
* 通过代理对象调用方法首先进入这个方法
* @param proxy 代理对象
* @param method 被调用的方法
* @param 方法的参数
*/
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
System.out.println("############JDK动态代理#########");
Object result = null;
System.out.println("我准备说hello");
// //执行方法,相当于调用helloServiceImpl类的sayHello方法
// //此invoke方法为Method类里面的incoke方法,而不是reflect里面的invoke方法
// //此方法实现真正的由接口调用实现类的方法
result =method.invoke(target, args);
// //反射方法后调用
System.out.println("我说过hello了");
return result;
}
}
对应的测试类为:
public class HelloServiceMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
//生成一个代理类对象
HelloServiceProxy HelloHandler = new HelloServiceProxy();
//代理接口
HelloService proxy = (HelloService)HelloHandler.bind(new HelloServiceImpl());
proxy.sayHello("zhang san");
}
}
CGlib动态代理:
JDK代理需要我们提供接口,必须有接口才能够实现动态,静态代理的过程,而CGlib可以不用提供接口,仅提供实现类就可以完成动态代理的工作,当然也可以完成有接口的动态代理,当然这个就体现不了CGlib的优势。重新设计一个符合CGlib使用的动态代理类:
public class HelloServiceCGlib implements MethodInterceptor{
private Object target;
public Object getInstance (Object target){
this.target = target;
//下面类似于JDK动态代理的绑定过程
Enhancer enhancer = new Enhancer();
//指定父类,不必指定接口
enhancer.setSuperclass(this.target.getClass());
//回调方法
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
System.out.println("###########我是CGLIB###########");
//反射方法的调用
System.out.println("我准备说hello");
Object returnObj = proxy.invokeSuper(obj, args);
System.out.println("我说过hello了");
return returnObj;
}
}
对应的测试类:
public class HelloServiceMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
//生成一个代理类对象
//cglib需要指定父类和回调方法。当然cglib也可以与Java动态代理一样面向接口,因为本质是继承。
HelloServiceCGlib HelloHandler = new HelloServiceCGlib();
//代理接口
HelloService proxy = (HelloService)HelloHandler.getInstance(new HelloServiceImpl());
proxy.sayHello("zhang san");
}
}
测试结果为: