代理模式与AOP等
参考https://course.study.163.com/480000005493360/lecture-480000036686223
静态代理:
接口类:
public interface GameFactory {
public String make();
}
委托类(被代理类):
public class GameBoyFactory implements GameFactory {
public String make() {
return "GameBoy";
}
}
public class Ps4Factory implements GameFactory {
public String make() {
return "ps4";
}
}
代理类:
public class SdhProxy implements GameFactory{
private GameFactory realFactory;
public SdhProxy(GameFactory realFactory) {
this.realFactory = realFactory;
}
public void setRealFactory(GameFactory realFactory) {
this.realFactory = realFactory;
}
public String make() {
pre();
System.out.println(realFactory.make());
post();
return null;
}
private static void pre( ){
System.out.println("pre");
}
private static void post( ){
System.out.println("post");
}
}
调用者:
public class Caller {
public static void main(String[] args ){
GameFactory proxy = new SdhProxy(new GameBoyFactory());
proxy.make();
((SdhProxy) proxy).setRealFactory(new Ps4Factory());
proxy.make();
}
}
输出:
pre
GameBoy
post
pre
ps4
post
动态代理:
代理类:
public class SdhProxy2 implements InvocationHandler {
Object target; //被代理对象
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy(){
//生成代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long pre = pre();
Object result = method.invoke(target, args);
System.out.println(result);
long post = post();
return result+"--"+(post-pre);
}
private static long pre( ){
return System.currentTimeMillis();
}
private static long post( ){
return System.currentTimeMillis();
}
}
将调用者的执行代码改为:
SdhProxy2 proxy2 = new SdhProxy2();
GameFactory target = new GameBoyFactory();
proxy2.setTarget(target);
GameFactory pro = (GameFactory) proxy2.getProxy();
System.out.println(pro.make());
target = new Ps4Factory();
proxy2.setTarget(target);
System.out.println(pro.make());
输出:
GameBoy
GameBoy–0
ps4
ps4–0
注意动态代理可以提供到方法级的代理。比如接口类增加了一个方法design(),而代理类并不想管这个方法。
//接口类:
public interface GameFactory {public String make();
public String design();
}
//委托类(被代理类):
public class GameBoyFactory implements GameFactory {public String make() {
return "GameBoy";
}
public String design() {
return null;
}
}
public class Ps4Factory implements GameFactory {
public String make() {
return "ps4";
}
public String design() {
return null;
}
}
代理类SdhProxy2与调用者Caller都不需做任何变更,输出结果也不变。而如果用的是静态代理SdhProxy,它将不得不实现其并不关心的design()方法。
一些相关问题:
比较于CGLIB动态代理,为什么JDK动态代理只能代理实现了接口的类?
其实也简单,看看被圈起来的代码:
可参考的分析文章1,2:生成的代理类继承了Proxy类,由于java是单继承,所以代理对象只能声明为接口。
我实操了一下,确实getProxy()返回的代理对象只能被转为接口类型,否则会报错。
JDK 动态代理中,被代理对象(目标对象)调用自己的另一个方法,会经过代理对象么?1
解答:被代理对象(目标对象)调用内部方法的是本身,被调用的方法不会经过代理对象。
" class="reference-link">一些其他相关例子3:
RequestMapping可以生效,但是切面LoggedCheck不生效。为什么?
参考答案:AOP是基于JDK动态代理和CGLib,前者只能代理接口方法,所以不能代理static方法,后者也不支持代理static方法? 而@RequestMapping并不是AOP实现。
AOP只能增强public方法吗?
参见本博——-前海微众银行面经(部分) 的一面部分
- 面试必问系列之JDK动态代理 注:文中的将代理对象的class文件落盘的方法
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
亲测无效。据https://blog.csdn.net/MrYushiwen/article/details/111473126,JDK1.8以后应该用System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
,亲测有效。 ↩︎ ↩︎ - java动态代理为什么需要基于接口 ↩︎
- B站极海Channel ↩︎
还没有评论,来说两句吧...