代理模式(proxy)
代理模式主要有两个功能:1.目标类委托代理类做代理,想访问目标类需要通过代理类来访问;2.在代理过程中,可以通过代理类对目标类或者目标方法做功能性扩展(如AOP)
1.静态代理:
个人认为,静态代理模式就是装饰模式,这里无需在写一遍,装饰模式的相关介绍请参考上一篇博文:https://blog.csdn.net/l450741881/article/details/88837064
2.动态代理
动态代理可以在不实现接口的情况下在内存中生成代理类以达到代理的目的,动态代理中按照目标类是否实现了某接口分为两类,1.jdk接口代理,2.cglib代理
jdk接口代理
这种代理主要是由java提供的java.lang.reflect.Proxy类中newProxyInstance方法,通过反射来实现的,
newProxyInstance(ClassLoader loader,class<?>[] interfaces,InvocationHandler h)
- loader:代表与目标对象相同的类加载器-------目标对象.getClass().getClassLoader(),或者自己根据自己的需求设置类加载器
- interfaces:代表与目标对象实现的所有的接口字节码对象数组----数组因为目标类可以有多个接口
- h:具体的代理的操作,InvocationHandler接口
而InvocationHandler接口,需要实现方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
- proxy:代理类生成的目标接口类型的代理对象,下面例子中有阐述
- method:调用目标类方法
- args:调用目标类方法参数
代码实现该动态代理:首先创建目标接口和目标类:
public interface ITarget {
String doSomeThing(String th);
}
public class TargetClass implements ITarget{
@Override
public String doSomeThing(String th){
System.out.println("running...."+th);
return th;
}
}
然后创建代理类:
public class ProxyClass {
//维护一个目标对象
private Object target;
public ProxyClass(Object target){
this.target=target;
}
//给目标对象生成代理对象
public Object getProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start.....");
if (proxy instanceof ITarget)
System.out.println("proxy is ITarget.....");
Object returnValue = method.invoke(target, args);
System.out.println("end.....");
return returnValue;
}
}
);
}
}
用代理的方式执行目标代码:
TargetClass target = new TargetClass();
ITarget proxy = (ITarget)new ProxyClass(target).getProxyInstance();
System.out.println("return:"+proxy.doSomeThing("hello!"));
执行结果:
start.....
proxy is ITarget.....
running....hello!
end.....
return:hello!
可见invoke中的proxy参数是代理对象,并且生成的代理对象是接口类.
cglib代理
cglib代理可以代理没有接口的类,原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,但因为采用的是继承,所以不能对final修饰的类进行代理,JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
创建目标类:
public class TargetClass2 {
public String doSomeThing(String th){
System.out.println("running...."+th);
return th;
}
}
创建代理类:
public class ProxyClass2 {
public <T> Object getProxyInstance(T t){
Enhancer en = new Enhancer(); //帮我们生成代理对象
en.setSuperclass(t.getClass());//设置要代理的目标类
en.setCallback(new MethodInterceptor() {//代理要做什么
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("执行方法前。。。");
//调用原有方法
Object invoke = methodProxy.invokeSuper(object, args);
// Object invoke = method.invoke(t,args); 作用等同与上面。
System.out.println("执行方法后。。。");
return invoke;
}
});
Object proxyObj = en.create();//生成代理对象
return proxyObj;
}
}
执行方法:
TargetClass2 target = new TargetClass2();
TargetClass2 proxy = (TargetClass2)new ProxyClass2().getProxyInstance(target);
System.out.println("return:"+proxy.doSomeThing("hello!"));
执行结果:
执行方法前。。。
running....hello!
执行方法后。。。
return:hello!
Spring AOP中如果目标类实现接口用的是jdk接口代理,没有实现接口使用的是cglib代理.