1 什么是代理
代理模式: 代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的租房、买房中介。
2 代理模式的分类
静态代理: 我们通常都很熟悉。有一个写好的代理类,实现与要代理的类的一个共同的接口。
动态代理: 其实是一种方便运行时候动态的处理代理方法的调用机制,通过代理可以让调用者和实现者之间解耦,例如RPC调用,对于我们调用者来说我就是想对用远程的那个方法,对于内部寻址啊,序列化反序列化等等这些交给代理来就行了。
3 动态代理
3.1 分类
JDK动态代理
利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类。
在调用具体方法前调用InvokeHandler来处理。
CGLiB动态代理
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口。
二者区别:
JDK只能针对接口不能针对类实现代理。
CGLib通过继承方式实现代理。所以类或方法最好不要声明成final,对于final类或方法,是无法继承的。
Spring如何选择用JDK还是CGLiB?
1)当Bean实现接口时,Spring就会用JDK的动态代理。
2)当Bean没有实现接口时,Spring使用CGlib是实现。
3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class=“true”/>)。
3.2 实现条件
在java中规定,要想产生一个对象的代理对象,那么这个对象必须要有一个接口,所以我们第一步就是设计这个对象的接口,在接口中定义这个对象所具有的行为(方法)。它通过在运行时创建代理类,来适应变化。主要用到的是Reflect中的Proxy和InvocationHandler类。
3.3 应用场景:
当用户要调用一个类的方法时,用户可以通过调用代理,代理通过接口调用原来的类的方法,代理在把方法给用户前可以添加一些方法,如错误日志,用户类的方法运行的时间来监听类方法的性能。当代理完成时候就是当代理调用方法时候,就会启动InvocationHandler里的invoke方法(在测试类中代理类调用方法时有所体现)。
3.4 具体实例
代理类:
import com.danger.user.service.UserInfoService;
import com.danger.user.service.UserInfoServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogHander implements InvocationHandler {
private Object targetObject;
public Object newProxyInstance(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 {
System.out.println("start-->>" + method.getName());//方法执行前的操作
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
Object ret = null;
try {
ret = method.invoke(targetObject, args);
} catch (Exception e) {
e.printStackTrace();
System.out.println("error-->>" + method.getName());//出现异常时的操作
throw e;
}
return ret;
}
public static void main(String[] args) throws Exception {
//代理类
LogHander logHander = new LogHander();
//获得代理对象
UserInfoService userInfoService = (UserInfoService) logHander.newProxyInstance(new UserInfoServiceImpl());
//调用代理对象的sing方法
String retValue = userInfoService.sing("冰雨");
System.out.println(retValue);
//调用代理对象的dance方法
String value = userInfoService.dance("江南style");
System.out.println(value);
}
}
接口:
public interface UserInfoService {
/**
* 唱歌
* @param name
* @return
*/
String sing(String name);
/**
* 跳舞
* @param name
* @return
*/
String dance(String name);
}
实现接口的目标对象
import org.springframework.stereotype.Service;
@Service
public class UserInfoServiceImpl implements UserInfoService{
@Override
public String sing(String name) {
return "唱"+name+"歌!好听!";
}
@Override
public String dance(String name) {
return "跳"+name+"舞!好看!";
}
}
运行代理类中 的main方法,可以看到如下打印信息:
start-->>sing
冰雨
唱冰雨歌!好听!
start-->>dance
江南style
跳江南style舞!好看!
newProxyInstance 方法用来返回一个代理对象,这个方法总共有3个参数,
ClassLoader loader 用来指明生成代理对象使用哪个类装载器,
Class<?>[] interfaces 用来指明生成哪个对象的代理对象,通过接口指定,
InvocationHandler h 用来指明产生的这个代理对象要做什么事情。
所以我们只需要调用newProxyInstance方法就可以得到某一个对象的代理对象了。
参考: > https://www.cnblogs.com/xnfTosharing/p/11321465.html