一.JDK代理实现
接口类
public interface UserManager {
void addUser(@NotBlank String username, @NotNull(message = "javax.validation.constraints.NotNull.message") String password);
void delUser(int userId);
String findUserById(int userId);
}
实现类
public class UserManagerImpl implements UserManager {
@Override
public void addUser(String username, String password) {
System.out.println("addUser:" + username + "," + password);
}
@Override
public void delUser(int userId) {
System.out.println("delUser:" + userId);
}
@Override
public String findUserById(int userId) {
System.out.println("findUserById:" + userId);
return String.valueOf(userId);
}
}
代理类
public class SecurityHandler implements InvocationHandler {
private Object targetObject;
public Object createProxyInstanceObject(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
checkSecurity();
return method.invoke(targetObject,args);
}
private void checkSecurity(){
System.out.println("-----------checkSecurity----------");
}
}
二.CgLib代理实现
实现类
public class UserService {
public void addUser(String username, String password) {
System.out.println("addUser:" + username + "," + password);
}
public void delUser(int userId) {
System.out.println("delUser:" + userId);
}
public String findUserById(int userId) {
System.out.println("findUserById:" + userId);
return String.valueOf(userId);
}
}
代理类
public class CglibProxy implements MethodInterceptor {
private Object targetObject;
public Object createProxyInstanceObject(Object targetObject) {
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetObject.getClass());
enhancer.setCallback(this);
return enhancer.create();
//return targetObject;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = null;
//obj = methodProxy.invokeSuper(o, objects);
obj = method.invoke(targetObject, objects);
after();
return obj;
}
private void before() {
System.out.println("-----------before----------");
}
private void after() {
System.out.println("-----------after----------");
}
}
三.测试
public class App {
public static void proxyManager() {
SecurityHandler securityHandler = new SecurityHandler();
UserManager userManager = (UserManager) securityHandler.createProxyInstanceObject(new UserManagerImpl());
userManager.addUser("张飞", null);
}
public static void proxyService() {
SecurityHandler securityHandler = new SecurityHandler();
UserService userService = (UserService) securityHandler.createProxyInstanceObject(new UserService());
userService.addUser("李四", null);
}
public static void main(String[] args) {
cglibProxyManager();
}
public static void cglibProxyService() {
CglibProxy proxy = new CglibProxy();
UserService userService = (UserService) proxy.createProxyInstanceObject(new UserService());
userService.findUserById(1234);
}
public static void cglibProxyManager() {
CglibProxy proxy = new CglibProxy();
UserManager userManager = (UserManager) proxy.createProxyInstanceObject(new UserManagerImpl());
userManager.findUserById(1234);
}
}
运行结果会发现方法proxyService报错。
提出问题:
1.Enhancer类的作用
生成代理类,用来继承被代理对象
2.obj.invoke 和 obj.invokeSuper两种写法的区别
一般使用invokeSuper(obj,args)方法。执行原始类的方法。方法.invoke,这是执行生成子类的方法。如果传入的obj就是子类的话,会发生内存溢出,因为子类的方法不停的进入intercept方法,而这个方法又去调用子类的方法,两个方法直接循环调用了。
我们来看看MethodProxy,原始类里每一个方法都会在动态的子类里有一个对应的MethodProxy,而一个MethodProxy又对应了两个动态生成的FastClass类,一个是对应原始方法,一个对应新生成的子类,MethodProxy.invokeSuper就是交给对应原始方法那个FastClass,MethodProxy.invoke交给另一个。
3.proxyService方法为什么会报错
核心在于ProxyGenerator.generateProxyClass
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
return var4;
}
private byte[] generateClassFile() {
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
Class[] var1 = this.interfaces;
int var2 = var1.length;
int var3;
Class var4;
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
Method[] var5 = var4.getMethods();
int var6 = var5.length;
for(int var7 = 0; var7 < var6; ++var7) {
Method var8 = var5[var7];
this.addProxyMethod(var8, var4);
}
}
Iterator var11 = this.proxyMethods.values().iterator();
List var12;
while(var11.hasNext()) {
var12 = (List)var11.next();
checkReturnTypes(var12);
}
Iterator var15;
try {
this.methods.add(this.generateConstructor());
var11 = this.proxyMethods.values().iterator();
while(var11.hasNext()) {
var12 = (List)var11.next();
var15 = var12.iterator();
while(var15.hasNext()) {
ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
this.methods.add(var16.generateMethod());
}
}
this.methods.add(this.generateStaticInitializer());
} catch (IOException var10) {
throw new InternalError("unexpected I/O Exception", var10);
}
if (this.methods.size() > 65535) {
throw new IllegalArgumentException("method limit exceeded");
} else if (this.fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
} else {
this.cp.getClass(dotToSlash(this.className));
this.cp.getClass("java/lang/reflect/Proxy");
var1 = this.interfaces;
var2 = var1.length;
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
this.cp.getClass(dotToSlash(var4.getName()));
}
this.cp.setReadOnly();
ByteArrayOutputStream var13 = new ByteArrayOutputStream();
DataOutputStream var14 = new DataOutputStream(var13);
try {
var14.writeInt(-889275714);
var14.writeShort(0);
var14.writeShort(49);
this.cp.write(var14);
var14.writeShort(this.accessFlags);
var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
var14.writeShort(this.interfaces.length);
Class[] var17 = this.interfaces;
int var18 = var17.length;
for(int var19 = 0; var19 < var18; ++var19) {
Class var22 = var17[var19];
var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
}
var14.writeShort(this.fields.size());
var15 = this.fields.iterator();
while(var15.hasNext()) {
ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
var20.write(var14);
}
var14.writeShort(this.methods.size());
var15 = this.methods.iterator();
while(var15.hasNext()) {
ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
var21.write(var14);
}
var14.writeShort(0);
return var13.toByteArray();
} catch (IOException var9) {
throw new InternalError("unexpected I/O Exception", var9);
}
}
}
1.在需要继承proxy类获得有关方法和InvocationHandler构造方法传参的同时,java不能同时继承两个类,我们需要和想要代理的类建立联系,只能实现一个接口
2.需要反射获得代理类的有关参数,必须要通过某个类,反射获取有关方法,如本次测试用的 :printSomeThing
3.成功返回的是object类型,要获取原类,只能继承/实现,或者就是那个代理类
4.对具体实现的方法内部并不关心,这个交给InvocationHandler.invoke那个方法里去处理就好了,我只想根据你给我的接口反射出对我有用的东西。
5.考虑到设计模式,以及proxy编者编写代码的逻辑使然
结论:
JDK代理和Cglib代理的区别
JDK代理 | Cglib代理 | |
实现 | InvocationHandle 底层使用反射机制进行方法的调用r | MethodInterceptor 底层将方法全部存入一个数组中,通过数组索引直接进行方法调用 |
优点 | 不需要硬编码接口,代码复用率高 | 可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口 |
缺点 | 只能够代理实现了接口的委托类 | 不能对final类以及final方法进行代理 |