前言
代理模式可以在访问目标对象的基础上,增强额外的功能。
代理模式分为静态代理和动态代理,但是静态代理的代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护。动态代理便解决了此问题。
动态代理在Spring,mybatis等框架中有广泛的应用。所以在了解框架源码前需要先了解动态代理。
1.java反射
动态代理以java反射为基础。在了解动态代理前,需要先了解java反射机制。
Java 反射机制在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种 动态的获取信息 以及 动态调用对象的方法 的功能称为 java 的反射机制。
如上看着着实懵逼,看下代码:
例如有一个UserInfo对象
public class UserInfo {
private Long id;
private String name;
public void init() throws Exception {
System.out.println("这里是 UserInfo init");
}
public void init(String a) throws Exception {
System.out.println("这里是 UserInfo init a:"+a);
}
public void init(String a,Integer b) throws Exception {
System.out.println("这里是 UserInfo init a:"+a+" b:"+b);
}
}
那么创建此对象有以下几种方式:
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
//普通方式进行创建
UserInfo userInfo = new UserInfo();
//通过反射机制进行创建
Class userInfoClass = UserInfo.class;
UserInfo userInfo1 = (UserInfo) userInfoClass.newInstance();
//反射进行创建
Class userInfoClass2= Class.forName("com.example.model.UserInfo");
UserInfo userInfo2 = (UserInfo) userInfoClass2.newInstance();
}
通过反射执行对象中的方法
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class userInfoClass = UserInfo.class;
Object userinfo = userInfoClass.newInstance();
// 执行init(String a) 方法
Method init = userInfoClass.getMethod("init", new Class[]{String.class});
init.invoke(userinfo,new Object[]{"123"});
// 执行init(String a,Integer b)方法
Method init2 = userInfoClass.getMethod("init", new Class[]{String.class,Integer.class});
init2.invoke(userinfo,new Object[]{"123",123});
}
输出:
这里是 UserInfo init a:123
这里是 UserInfo init a:123 b:123
详细可参考 java反射机制详解
java反射学习
2.java动态代理
java实现动态代理主要有两种,jdk动态代理和CGLIB动态代理。
jdk动态代理是jdk原生,不需要引用其他jar包,但是只能代理接口,如果需要对类进行动态代理则需要引用CLIGB动态代理。
2.1 jdk动态代理
Proxy
提供了创建动态代理类和实例的静态方法
InvocationHandler
是由代理实例的调用处理程序实现的接口。
代理者需要实现InvocationHandler
接口
示例:
IUserInfoService.java
public interface IUserInfoService {
void addUserInfo(UserInfo userInfo);
}
接口实现类UserInfoService.java
// 这里加上事务注解
@Transactional
public class UserInfoService implements IUserInfoService {
@Override
public void addUserInfo(UserInfo userInfo) {
System.out.println("保存UserInfo");
}
}
代理类ProxyHandler
public class ProxyHandler implements InvocationHandler {
private Object object;
public ProxyHandler(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法调用之前");
//是否有开启事务注解
boolean annotationPresent = object.getClass().isAnnotationPresent(Transactional.class);
if(annotationPresent){
System.out.println("开启事务");
}
Object invoke = method.invoke(object, args);
if(annotationPresent){
System.out.println("提交事务");
}
return invoke;
}
}
Test.java
public class Test {
public static void main(String[] args) {
IUserInfoService userInfoService = new UserInfoService();
//获取代理实现类
// 由下面代理类可见,这里其实等于 IUserInfoService o = new UserServiceProxy()
//然后UserServiceProxy这个对UserInfoService进行了代理。
IUserInfoService o = (IUserInfoService)Proxy.newProxyInstance(userInfoService.getClass().getClassLoader(),userInfoService.getClass().getInterfaces(),new ProxyHandler(userInfoService));
// 通过代理类实现方法,
o.addUserInfo(new UserInfo());
//保存代理类.class文件
createClassFile(o.getClass(),"UserServiceProxy");
}
public static void createClassFile(Class clazz, String proxyName) {
// 根据类信息和提供的代理类名称,生成字节码
byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
String paths = clazz.getResource("/").getPath();
System.out.println(paths);
FileOutputStream out = null;
try {
//保留到硬盘中
out = new FileOutputStream(paths + proxyName + ".class");
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
代理类
public final class UserServiceProxy extends Proxy implements IUserInfoService {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public UserServiceProxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final UserInfo getUserInfoById(Long var1) throws {
try {
return (UserInfo)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void addUserInfo(UserInfo var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.example.proxy.IUserInfoService").getMethod("getUserInfoById", new Class[]{Class.forName("java.lang.Long")});
m4 = Class.forName("com.example.proxy.IUserInfoService").getMethod("addUserInfo", new Class[]{Class.forName("com.example.model.UserInfo")});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
通过代理,java动态生成了UserServiceProxy
类来对目标对象进行代理。
2.2 CLIGB动态代理
引入jar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
被代理的类UserInfoService
public class UserInfoService implements IUserInfoService {
@Override
public void addUserInfo(UserInfo userInfo) {
System.out.println("保存UserInfo");
}
}
代理类,这里要实现MethodInterceptor
接口,在方法执行的时候会调用intercept
方法,这一点和jdk代理类似
public class CglibHandler implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行方法");
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("执行方法之后");
return o1;
}
}
接下来进行测试
public class Test {
public static void main(String[] args) {
//它是一个字节码增强器,可以用来为无接口的类创建代理 ,与JDK的Proxy类类似
Enhancer enhancer = new Enhancer();
// 设置被代理类
enhancer.setSuperclass(UserInfoService.class);
// 设置代理类
enhancer.setCallback(new CglibHandler());
//获取代理类
UserInfoService hello = (UserInfoService)enhancer.create();
// 执行方法,此会调用 代理类的intercept方法
hello.addUserInfo(new UserInfo());
}
}
输出:
执行方法
保存UserInfo
执行方法之后