一. 动态代理模式介绍
代理模式
(Proxy Pattern):
给某⼀个对象提供⼀个代理,并由代理对象控制对原对象的引⽤。代理模式 的英⽂叫做Proxy
,它是⼀种对象结构型模式,代理模式分为静态代理和动态代理,我们来介绍动态代理。
举例:
创建⼀个抽象类,
Person
接⼝,使其拥有⼀个没有返回值的
doSomething
⽅法。
package com.lagou.dynamicproxy;
public interface Person {
public void doSomething();
}
创建⼀个名为
Bob
的
Person
接⼝的实现类,使其实现
doSomething
⽅法
package com.lagou.dynamicproxy;
public class Bob implements Person {
@Override
public void doSomething() {
System.out.println("Bob doing Something");
}
}
创建
JDK
动态代理类,使其实现
InvocationHandler
接⼝。拥有⼀个名为
target
的变量,并创建
getTa rget
获取代理对象⽅法
package com.lagou.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKDynamicProxy implements InvocationHandler {
// 声明被代理的对象
private Person person;
//构造函数
public JDKDynamicProxy(Person person) {
this.person = person;
}
//获取代理对象
public Object getTarget(){
Object proxyInstance = Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), this);
return proxyInstance;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("对原方法进行了前置增强");
//原方法执行
Object invoke = method.invoke(person, args);
System.out.println("对原方法进行了后置增强");
return invoke;
}
}
创建
JDK
动态代理测试类
J DKDynamicTest
package com.lagou.dynamicproxy;
public class proxyTest {
public static void main(String[] args) {
System.out.println("不使用代理类,调用doSomething");
Person person = new Bob();
person.doSomething();
System.out.println("--------------------------");
System.out.println("使用代理类,调用doSomething");
Person proxy = (Person) new JDKDynamicProxy(new Bob()).getTarget();
proxy.doSomething();
}
}
二. 模式在Mybatis中实现:
代理模式可以认为是
Mybatis
的核⼼使⽤的模式,正是由于这个模式,我们只需要编写
Mapper.java
接 ⼝,不需要实现,由
Mybati s
后台帮我们完成具体
SQL
的执⾏。
当我们使⽤
Configuration
的
getMapper
⽅法时,会调⽤
mapperRegistry.getMapper
⽅法,⽽该⽅法⼜
会调⽤
mapperProxyFactory.newInstance(sqlSession)
来⽣成⼀个具体的代理:
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new
ConcurrentHashMap<Method, MapperMethod>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new
Class[] { mapperInterface },
mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession,
mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
在这⾥,先通过
T newInstance(SqlSession sqlSession)
⽅法会得到⼀个
MapperProxy
对象,然后调⽤
TnewInstance(MapperProxy mapperProxy)
⽣成代理对象然后返回。⽽查看
MapperProxy
的代码,可以看到如下
内容:
public class MapperProxy<T> implements InvocationHandler, Serializable {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
⾮常典型的,该
MapperProxy
类实现了
InvocationHandler
接⼝,并且实现了该接⼝的
invoke
⽅法。通 过这种⽅式,我们只需要编写
Mapper.java
接⼝类,当真正执⾏⼀个
Mapper
接⼝的时候,就会转发给
MapperProxy.invoke
⽅法,⽽该⽅法则会调⽤后续的
sqlSession.cud>executor.execute>prepareStatement
等
⼀系列⽅法,完成
SQL
的执⾏和返回。