- Spring框架对于IT屌丝们来说应该都不陌生。个人观点,Spring之所以能够经久不息的在IT独领风骚,原因在于它自身比较骚的三大特点:一、IOC大家经常说的控制反转。二、AOP面向切面的编程。三、自身属于比较轻量级的开发框架。而其中AOP面向切面的编程思想贯穿整个框架的运行全过程。我们将分几个部分共同探讨Spring AOP。本篇博文主要叙述AOP运行中经常用到的java JDK代理。
为什么要创建代理
代理,顾名思义可以理解为真实目标和调用者之间的过程态,可以通过代理去操作目标类。可以说在整个spring框架中代理随处可见,那么使用代理的作用是什么呢?spring通过使用代理,可以更加灵活的凸显java面向对象的编程优势,通过动态代理,可以对目标类加入通知或者拦截器,从而可以提供切面功能,或者提供灵活的可配置的参数
public interface DoService {
//添加
public void add();
//查询
public void selectInfo();
//更新
public void update();
}
public class DoServiceImpl implements DoService{
//用户名
private String userName;
@Override
public void add() {
System.out.println("添加的方法");
}
@Override
public void selectInfo() {
System.out.println("查询的方法");
}
@Override
public void update() {
System.out.println("更新的方法");
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
比如上述代码提供了实现更新,添加,查询的接口DoService及其实现类DoServiceImpl。现在如果想对业务实现类中每个方法执行前加上打印日志的逻辑,那么在没用代理之前,只能在每个方法前手动把要新增的业务逻辑加上去。那么有了代理以后呢,这些要新增的操作,我们就可以在代理类中公共的地方去完成,而不用每个方法逐一添加。
JDK动态代理的创建过程
对于特定对象JDK代理实现主要包含三个步骤:1、创建业务接口及实现业务接口的实现类(目标类)。2、实现InvocationHandler接口类(实现创建代理类的方法),并且对接口中invoke方法进行重载,这个invoke方法将在后面生成的代理对象中每个方法体中被调用。3、根据目标类及实现的InvocationHandler类生成目标代理类Proxcy0。具体实例如下所示:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.service.impl.DoServiceImpl;
/**
* 代理工厂类
* @author hyj
*
*/
public class JDKProxyFactory implements InvocationHandler{
//被代理的目标对象
private Object obj;
/**
* 通过代理工厂的方式来创建代理类
* @param obj 要代理的类的对象(该对象为Proxcy的子类)
* @return
*/
public Object createProxyIntance(Object obj){
this.obj=obj;
//第一个参数是目标对象的类加载器
//第二个参数是目标对象实现的接口
//第三个参数传入一个InvocationHandler实例,该参数和回调有关系。
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);
}
//该invoke方法在生成的目标代理对象的方法体中被调用
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object proxyObject=null;
DoServiceImpl ds=(DoServiceImpl)obj;
if(ds.getUserName()!=null){
proxyObject= method.invoke(ds, args);
}else{
System.out.println("用户名为空,已拦截");
}
return proxyObject;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
//测试类
import cn.aop.JDKProxyFactory;
import cn.service.DoService;
import cn.service.impl.DoServiceImpl;
public class TestHappy {
public static void main(String[] args) {
JDKProxyFactory jpf=new JDKProxyFactory();
DoService ds=(DoService)jpf.createProxyIntance(new DoServiceImpl("fsf"));
ds.selectInfo();
}
}
生成的JDK动态代理对象长什么样?
通过研究源码可知,创建代理对象调用的是Proxcy中提供的方法。Proxcy对象是生成的代理对象的父类。Proxcy中有个InvocationHandler属性是proctect类型的,可以看出该属性就是提供给Proxcy子类使用的。下面是生成代理对象的源码。
public final class $Proxy11extends Proxy implements IStudent{
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
public $Proxy11(InvocationHandler paramInvocationHandler) throws {
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject) throws {
try {
return ((Boolean)this.h.invoke(this, m1,new Object[] { paramObject })).booleanValue();
} catch (RuntimeException localRuntimeException) {
throw localRuntimeException;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode() throws {
try {
return ((Integer)this.h.invoke(this, m0,null)).intValue();
} catch (RuntimeException localRuntimeException) {
throw localRuntimeException;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void add(String paramString) throws {
try {
this.h.invoke(this, m3, new Object[] { paramString });
return;
} catch (RuntimeException localRuntimeException) {
throw localRuntimeException;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
//update selectInfo方法如上述add方法
public final String toString()throws {
try {
return ((String)this.h.invoke(this, m2,null));
} catch (RuntimeException localRuntimeException) {
throw localRuntimeException;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
Static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",new Class[0]);
m3 = Class.forName("spring_dynamic_proxy.IStudent").getMethod("say",new Class[] { Class.forName("java.lang.String") });
m2 = Class.forName("java.lang.Object").getMethod("toString",new Class[0]);
return;
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
} catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
通过代理对象的源码就看出来,为什么测试类中调用目标对象的方法就会触发InvocationHanler类中的invoke方法了吧。
JDK动态代理就先分析到这里
未完。。。。待续。。。。晚安
本文由 xiesai 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为:2018-10-14 00:00:00