一、背景
1.在jdk1.3之后引入了一种称之为动态代理(Dynamic Proxy)的机制,使用该机制,我们可以为指定的接口在系统运行期间动态地生成代理对象,从而帮助我们走出最初使用静态代理实现AOP的窘境。
二、基础讲解
1.举个栗子
2.分析
目标类:target,就是我们需要增强的那个类。
代理类:proxy,就是我们自定义的那个代理的对象。
连接点:joinpoint,连接点说白了就是我们的目标类里面所有的方法。
切入点:pointCut,切入点说白了就是那些在目标类中我们实际上增强的方法。
织入:weave,说白了就是将我们的代理类中需要增强的方法放入到目标类中去执行的过程,就叫织入。
三、代码
1.动态代理的实现主要由一个类和一个接口组成,即java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
2.IUserService.java
public interface IUserService {
public void request();
}
3.IUserServiceImpl.java
public class IUserServiceImpl implements IUserService{
@Override
public void request() {
System.out.println("this is userService");
}
}
4.RequestCostInvocationHandler.java
/**
* 代理类
*/
public class RequestCostInvocationHandler implements InvocationHandler {
private Object target;
public RequestCostInvocationHandler(Object target) {
this.target = target;
}
//被代理对象的任何方法被执行时,都会先进入这个方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("request".equals(method.getName())) {
long startTime = System.currentTimeMillis();
//执行目标对象的方法
method.invoke(target, args);
System.out.println("request cost的值为" + (System.currentTimeMillis() - startTime));
}
return null;
}
public IUserService getIUserviceProxy() {
IUserService userService = (IUserService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
return userService;
}
}
5.测试类
public static void main(String[] args) {
/**
* 在invoke方法编码指定返回的代理对象干的工作
* proxy : 把代理对象自己传递进来
* method:把代理对象当前调用的方法传递进来
* args:把方法参数传递进来
* 当调用代理对象的request()方法时,
* 实际上执行的都是invoke方法里面的代码,
* 因此我们可以在invoke方法中使用method.getName()就可以知道当前调用的是代理对象的哪个方法
*/
IUserService userService = new IUserServiceImpl();
RequestCostInvocationHandler requestCostInvocationHandler = new RequestCostInvocationHandler(userService);
requestCostInvocationHandler.getIUserviceProxy().request();
}
6.执行结果
this is userService
request cost的值为0
6.上面就是有关Jdk的动态代理的小栗子。
四 、mybatis核心设计思路
1.相信用过 mybatis 的小伙伴都能理解下面这段代码,通过roleMapper这个借口直接从数据库中拿到一个对象 Role role = roleMapper.getRole(3L);直觉告诉我,一个接口是不能运行的啊,一定有接口的实现类,可是这个实现类我自己没写啊,难道 mybatis 帮我们生成了?你猜的没错, mybatis 利用动态代理帮我们生成了接口的实现类,这个类就是 org.apache.ibatis.binding. MapperProxy ,我先画一下 UML 图, MapperProxy 就是下图中的 SubjectProxy 类.
2.和上面的 UML 类图对比一下,发现不就少了一个 SubjectImpl 类吗?那应该就是 SubjectProxy 类把 SubjectImple 类要做的事情做了呗,猜对了。 SubjectProxy 通过 SubjectImple 和 SubjectImple . xml 之间的映射关系知道自己应该执行什么 SQL 。所以 mybatis 最核心的思路就是这么个意思,细节之类的可以看源码,理清最主要的思路,看源码就能把握住重点。