分类
静态代理:一个代理只帮同一种人代理
动态代理:一个代理可以帮不同的人代理
静态代理
我画了一个草图,方便大家理解
典型的例子,房东要租房,找到了中介,叫中介帮忙租出去,客户租房直接去找中介,中介来操作租房的具体事宜。
//抽象角色
public interface Rent {
public void rent();
}
//房东
public class Host implements Rent {
@Override
public void rent(){
System.out.println("房东房屋出租。。。");
}
}
//中介
public class Proxy implements Rent{
private Host host;//房东
public Proxy() { }
public Proxy(Host host) {
this.host = host;
}
//租房
@Override
public void rent(){
seeHouse();
talk();
host.rent();
}
//看房
public void seeHouse(){
System.out.println("带顾客看房");
}
//陪顾客聊天
public void talk(){
System.out.println("陪顾客聊天");
}
}
//客户
public class Client {
public static void main(String[] args) {
//房东要租房
Host host = new Host();
//中介帮助房东租房
Proxy proxy = new Proxy(host);
//中介来完成租房的各种细节!
proxy.rent();
}
}
带顾客看房
陪顾客聊天
房东房屋出租。。。
动态代理
分类:
基于接口的动态代理—JDK动态代理
基于类的动态代理 — cglib 代理
现在用的较多的是javassist动态代理
下面是基于JDK动态代理实现的
//抽象角色
public interface Rent {
public void rent();
}
//房东
public class Host implements Rent {
@Override
public void rent(){
System.out.println("房东房屋出租。。。");
}
}
//中介
public class ProxyInvocationHandler implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类,每个代理实例都有一个关联的调用处理程序对象,它实现了接口InvocationHandler 。
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
// 处理代理实例上的方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//核心:本质利用反射实现!
Object result = method.invoke(rent, args);
talk();
return result;
}
//看房
public void seeHouse(){
System.out.println("带顾客看房");
}
//聊天
public void talk(){
System.out.println("陪顾客聊天");
}
}
//客户
public class Client {
public static void main(String[] args) {
//房东要租房
Host host = new Host();
//代理实例的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(host);
Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
proxy.rent();
}
}
带顾客看房
陪顾客聊天
房东房屋出租。。。
如果还没有看懂,不急,看看下面的,这是封装好了的,可以直接使用
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Auther: 罗罗
*/
public class ObjectProxy {
public static<T> T getProxy(final T t){
//=第一个参数,被代理类的类加载器
//第二个参数:被代理类实现的接口
//第三个参数:方法执行器
Object o = Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
//第一个参数:JDK的代理对象,别动
//第二个参数:执行的方法
//第三个参数:方法的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
//方法执行前
LogUtils.log(method,args);
//返回值是方法的返回值
result = method.invoke(t, args);
//方法执行后
LogUtils.log(method,args);
}catch (Exception e){
System.out.println(method.getName()+"方法出现异常:"+e.getCause()+"--->方法参数:"+ Arrays.asList(args));
}finally {
LogUtils.log(method,args);
}
return result;
}
});
return (T)o;
}
}
public static void main(String[] args) {
//注意,这里的proxy 必须是接口,不是接口就会报错
EatRiceImpl proxy = ObjectProxy.getProxy(new EatRice());
proxy.eatFruit();
}
报错如下
"C:\Program Files\Java\jdk1.8.0_144\bin\java.exe" "-javaagent:D:\IntelliJ IDEA\IntelliJ IDEA 2018.2.4\lib\idea_rt.jar=64270:D:\IntelliJ IDEA\IntelliJ IDEA 2018.2.4\bin" -bin\rep\com\fasterxml\jackson\core\jackson-annotations\2.10.0\jackson-annotations-2.10.0.jar"
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.luo.log.EatRice
at com.luo.test.LogTest.main(LogTest.java:14)
Process finished with exit code 1
原因是jdk动态代理生成的代理类,和接口的实现类是同一级的,无法转换。
看看为什么这么说,哈哈
public class EatRice implements EatRiceImpl{
@Override
public void eatFruit(int i,int b){
int c =i/b;
System.out.println("吃水果");
}
}
public class LogTest {
public static void main(String[] args) {
EatRiceImpl proxy = ObjectProxy.getProxy(new EatRice());
proxy.eatFruit(2,1);
Class<?>[] interfaces = proxy.getClass().getInterfaces();
System.out.println(Arrays.asList(interfaces));
}
}
"C:\Program Files\Java\jdk1.8.0_144\bin\java.exe" "-javaagent:D:\IntelliJ IDEA\IntelliJ IDEA 2018.2.4\lib\idea_rt.jar=50133:D:\IntelliJ IDEA\IntelliJ IDEA 2018.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar;C:\Program bin\rep\com\fasterxml\jackson\core\jackson-annotations\2.10.0\jackson-annotations-2.10.0.jar"
[interface com.luo.spring.log.EatRiceImpl]
吃水果
Process finished with exit code 0
是不是实现了同一个接口,所以是同一级的吧