代理
代理
一般对象可以通过公共接口完成自己所需完成的工作。但有些对象由于某些原因无法履行自己的日常职责。大图像加载时间过长、有的对象运行在远程计算机上、拦截发送到对象的消息等等。这时可以使用代理对象,通过它来承担客户端的职责,再将相应请求合理的转发给底层目标对象。
代理模式就是为了提供一个代理(Proxy)来控制对目标对象的访问。代理对象通常拥有一个几乎和实际对象相同的接口。它通常控制访问,并将请求合理的转发给底层真实对象。可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
静态代理
商家(Business类)邀请明星唱歌(调用SingStar的sing()方法),需要联系经纪人(代理Proxy)谈妥费用,经纪人(AssitantProxy)安排(这个过程中,设备、场务人员协调全部由助理做,如果没有助理,明星自己就得额外做这些事,所以代理扩展目标对象功能)明星演出。其中经纪人和明星同属一个公司(RecordCompany接口,代理对象与实际对象实现几乎相同的接口)
接口(公司):
package com.willem.proxy;
/**
* 唱片公司提供唱歌接口(舞台设备、工作人员)
*
* @author :wang_cgong
*
* Copyright (C) 2004-2017 All Rights Reserved.
*
* @Date 2017-08-21 15:08:12
*/
public interface RecordCompany {
public void Sing();
}
实际对象(明星)
package com.willem.proxy;
/**
* Created by wang_cgong on 2017-08-21 下午4:14.
* <p>
* Copyright (c) 2016- 2017, willem517782125@qq.com All Rights Reserved.
*/
/**
* 类描述(description): 歌星演出经过公司同意(实现RecordCompany)
*
* @作者(author): wang_cgong
* 时间(time): 2017-08-21 下午4:14
*
* @version: v 1.0.0
*
* @since JDK1.6
*/
public class SingStar implements RecordCompany{
@Override
public void Sing() {
System.out.println("《当你老了》\n《消愁》\n《穿越太平洋》\n《回忆那么伤》\n《告白气球》");
}
}
代理对象(经纪人)
package com.willem.proxy;
/**
* Created by wang_cgong on 2017-08-21 下午4:31.
* <p>
* Copyright (c) 2016- 2017, willem517782125@qq.com All Rights Reserved.
*/
/**
* 类描述(description): 助理(代理),通知(歌星)唱歌、和商家商谈出场费等等
*
* @作者(author): wang_cgong
* 时间(time): 2017-08-21 下午4:31
*
* @version: v 1.0.0
*
* @since JDK1.6
*/
public class AssitantProxy implements RecordCompany {
private RecordCompany target;
//用构造器注入,目标对象,只要目标对象实现了RecordCompany都可以
public AssitantProxy(RecordCompany target){
this.target=target;
}
@Override
public void Sing() {
System.out.println("南京演唱会准备就绪");
target.Sing();//歌星唱歌(等会调用代理,通过向上转型,其实底层调用的是SingStar的Sing()方法)
System.out.println("本站演唱会结束");
}
}
调用(商家)
package com.willem.proxy; /**
* Created by wang_cgong on 2017-08-21 下午4:46.
* <p>
* Copyright (c) 2016- 2017, willem517782125@qq.com All Rights Reserved.
*/
/**
* 类描述(description): 商家通过助理联系明星演出事宜
*
* @作者(author): wang_cgong
* 时间(time): 2017-08-21 下午4:46
*
* @version: v 1.0.0
*
* @since JDK1.6
*/
public class Business {
public static void main(String [] args){
SingStar target=new SingStar();
//代理对象。将目标对象传给代理对象(商家将相关演出事宜告知助理)
AssitantProxy proxy=new AssitantProxy(target);
//执行代理方法(助理执行自己的sing()方法,它在底层又调用了目标对象的sing()方法)
proxy.Sing();
}
}
总结:一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行。而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。
Aspectj
AspectJ是Eclipse基金组织的开源项目,多语法结构基本上已经成为AOP领域的标准。AspectJ是在编译时进行增强,所以它有一个专门的编译器来生成遵守Java字节码编码规范的Class文件。而Spring采用的是动态代理的方式,它并不需要有一个专门的编译器。故也称AspectJ为静态AOP实现,而Spring AOP为动态AOP实现。需要去官网下载aspectj-xxx.jar,双击安装。最后编译器安装支持aspectj的插件,项目关联aspectjrt.jar,选择Ajc编译器。编写java业务类,编写aspect切面
public aspect Logging{
public void logging(){
System.out.println("请输入验证码");
}
}
public aspect LoggingAspect{
void around():call(void logging()){
System.out.println("验证通过");
proceed;
System.out.println("欢迎登录");
}
}
动态代理
jdk自带动态代理
Java动态代理类位于java.lang.reflect包下:
1.java.lang.reflect.Proxy类
动态生产代理类和对象
2.java.lang.reflect.Proxy.InvocationHandler类
可以通过invoke()方法实现对真实角色的代理访问。
每次通过Proxy生成代理类对象都需要指定处理器对象。
抽象接口、真实对象类同上面的静态代理,不做改变。代理对象由Proxy类生成,所以不再需要代理类实现抽象接口(但真实对象还是需要实现接口),取而代之的是动态代理的处理程序接口(InvocationHandler)的实现。
类SinstarHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 类描述(description): 动态代理类对应的调用处理程序类
*
* @作者(author): wang_cgong
* 时间(time): 2017-08-23 上午10:48
*
* @version: v 1.0.0
*
* @since JDK1.6
*/
public class SinstarHandler implements InvocationHandler {
private SingStar target;
//构造器注入,spring的bean也有构造器注入属性
public SinstarHandler(SingStar target){
super();
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("南京演唱会准备就绪");
method.invoke(target,args);
System.out.println("本站演唱会结束");
return null;
}
}
客户端调用
package com.willem.dynamic.proxy;
/**
* Created by wang_cgong on 2017-08-23 下午2:28.
* <p>
* Copyright (c) 2016- 2017, willem517782125@qq.com All Rights Reserved.
*/
import java.lang.reflect.Proxy;
/**
* 类描述(description): 调用代理
*
* @作者(author): wang_cgong
* 时间(time): 2017-08-23 下午2:28
*
* @version: v 1.0.0
*
* @since JDK1.6
*/
public class Bussiness {
public static void main(String [] args){
SingStar target=new SingStar();
//生成SingStar的调用控制器对象
SinstarHandler handler=new SinstarHandler(target);
RecordCompany proxy= (RecordCompany)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{RecordCompany.class},handler);
//通过代理对象调用真正对象的方法
proxy.Sing();
}
}
问题来了,静态代理类调用了实际对象的方法,动态代理怎么就最终调用了实际对象的方法?
根据传递的被代理类(SingStar)及其实现的接口(RecordCompany)生成代理类的字节码加载到缓存中,但是加载到缓存中只是一个.java文件也不能用,所以底层还有编译等操作。如何生成代理类我们没法看到底层代码,但JDK源码有一段是生成动态代理类字节码的:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
因此我们可以用这段代码生成商家邀请明星演出,经过的(代理)助理的字节码:
package com.willem.dynamic.proxy;
/**
* Created by wang_cgong on 2017-08-24 上午10:55.
* <p>
* Copyright (c) 2016- 2017, willem517782125@qq.com All Rights Reserved.
*/
/**
* 类描述(description): JDK动态代理生成代理类字节码
*
* @作者(author): wang_cgong
* 时间(time): 2017-08-24 上午10:55
*
* @version: v 1.0.0
*
* @since JDK1.6
*/
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
public class DynamicProxyDemo {
public static void main(String[] args) throws Exception {
//根据传递的被代理类(SingStar)及其实现的接口(RecordCompany)生成代理类的字节码,即这一串参数[SingStar.class.getInterfaces()]提供了被代理类及其接口
byte[] classFile = ProxyGenerator.generateProxyClass("DynamicProxy", SingStar.class.getInterfaces());
FileOutputStream out = null;
try {
//在当前工作目录下生成动态代理类的class文件
out = new FileOutputStream(System.getProperty("user.dir") + "\\DynamicProxy.class");
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字节码如下反编译后:
import com.willem.dynamic.proxy.RecordCompany;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class DynamicProxy extends Proxy
implements RecordCompany
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public DynamicProxy(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final void Sing()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.willem.dynamic.proxy.RecordCompany").getMethod("Sing", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
}
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
public final class DynamicProxy extends Proxy implements
RecordCompany
JDK动态代理类默认继承了Proxy类,由于Java的单继承,JDK动态代理无法实现继承式代理(无法继承实现类,只能去实现实现类的接口),所以只支持接口代理。
proxy对象调用sing()方法:
public final void Sing()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
其实就转发到了控制器的invoke方法,控制器中method.invoke(target,args);通过反射调用目标对象的sing()方法。从而实现代理。
代理工厂
在工厂中用匿名内部类代替控制器类:
package com.willem.dynamic.proxy;
/**
* Created by wang_cgong on 2017-08-24 下午5:33.
* <p>
* Copyright (c) 2016- 2017, willem517782125@qq.com All Rights Reserved.
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 类描述(description): 匿名内部类代替调用处理器handler代理工厂
*
* @作者(author): wang_cgong
* 时间(time): 2017-08-24 下午5:33
*
* @version: v 1.0.0
*
* @since JDK1.6
*/
public class ProxyFactory {
private Object target;
//构造器注入目标对象
public ProxyFactory(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("开始事务");
Object returnValue=method.invoke(target,args);
System.out.println("事务结束");
return returnValue;
}
});
}
}
结果展示:
总结:JDK动态代理的代理对象在创建时,需要使用业务实现类所实现的接口作为参数(因为在后面代理方法时需要根据接口内的方法名进行调用)。如果业务实现类是没有实现接口而是直接定义业务方法的话,就无法使用JDK动态代理了。并且,如果业务实现类中新增了接口中没有的方法,这些方法是无法被代理的(因为无法被调用)。
invoke方法分析
接口,同名方法,不同参数
public interface JdkProxyInterface {
String doSomething(String thingsNeedParm);
String doSomething(String thingsNeedParm1,String thingsNeedParm2);
}
接口实现
public class SubjectIpml implements JdkProxyInterface {
@Override
public String doSomething(String thingsNeedParm) {
System.out.println("使用" + thingsNeedParm + "做了一些事情");
return "调用成功";
}
@Override
public String doSomething(String thingsNeedParm1, String thingsNeedParm2) {
System.out.println("使用" + thingsNeedParm1+"&"+thingsNeedParm2 + "做了一些事情");
return "调用成功";
}
}
代理
public class SubjectProxy implements InvocationHandler {
private JdkProxyInterface subject;
SubjectProxy(JdkProxyInterface subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//进行method过滤,如果是其他方法就不调用
if (method.getName().equals("doSomething")){
System.out.println("做某些事前的准备");
Object object = method.invoke(subject,args);
System.out.println("做某些事后期收尾");
return object;
}
if (method.getName().equals("equals")){
System.out.println("equals来啦");
Object object = method.invoke(subject,args);
System.out.println("equals走啦");
return object;
}
return "调用失败";
}
public JdkProxyInterface getProxy() {
return (JdkProxyInterface) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), this);
}
}
结果
CGLIB代理
cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承(重写父类(目标类)所有方法),final不能被重写,所以不能代理final方法。
目标类:
package com.willem.cglib; /**
* Created by wang_cgong on 2017-08-21 下午4:14.
* <p>
* Copyright (c) 2016- 2017, willem517782125@qq.com All Rights Reserved.
*/
/**
* 类描述(description): cglib代理,代理目标类都不需要实现接口了
*
* @作者(author): wang_cgong
* 时间(time): 2017-08-21 下午4:14
*
* @version: v 1.0.0
*
* @since JDK1.6
*/
public class SingStar {
public void sing() {
System.out.println("《当你老了》\n《消愁》\n《穿越太平洋》\n《回忆那么伤》\n《告白气球》");
}
public boolean test(String s){
System.out.println("测试Fastcalss如何根据下标定位方法:"+s);
return true;
}
}
代理工厂
package com.willem.cglib;
/**
* Created by wang_cgong on 2017-09-11 下午9:28.
* <p>
* Copyright (c) 2016- 2017, willem517782125@qq.com All Rights Reserved.
*/
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 类描述(description): Cglib代理工厂,在内存中动态生成被代理类的子类对象
*
* @作者(author): wang_cgong
* 时间(time): 2017-09-11 下午9:28
*
* @version: v 1.0.0
*
* @since JDK1.6
*/
public class CglibProxyFactory implements MethodInterceptor {
private Enhancer en=new Enhancer();
private Object target;
public CglibProxyFactory(Object target){
this.target=target;
}
public Object getProxyInstance() {
//通过增强类对象设置父类(目标对象类)
en.setSuperclass(target.getClass());
//设置回调函数(拦截器类)
en.setCallback(this);
//返回代理对象
//System.out.println(en.create());
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println(method.getName()+"执行前做的工作!");
//Object result=methodProxy.invokeSuper(obj,args);//相当于AOP的切点
//①methodProxy.invokeSuper(target,args);//错误
//②methodProxy.invoke(target,args);//正确
//③methodProxy.invoke(obj,args);//堆栈溢出发生循环调用
methodProxy.invokeSuper(obj,args);
//④method.invoke(target,args);//正确,但走的是JDK的invoke方法,通过反射来调用目标方法,那用cglib就无意义了
System.out.println(method.getName()+"执行后做的工作!");
return null;
}
}
客户端调用
package com.willem.cglib;
/**
* Created by wang_cgong on 2017-09-12 下午4:57.
* <p>
* Copyright (c) 2016- 2017, willem517782125@qq.com All Rights Reserved.
*/
/**
1. 类描述(description): Cglib代理工厂客户端调用
2. 3. @作者(author): wang_cgong
4. 时间(time): 2017-09-12 下午4:57
5. 6. @version: v 1.0.0
7. 8. @since JDK1.6
*/
public class Bussiness {
public static void main(String [] args){
SingStar target=new SingStar();
//保存生成的class文件
System.out.println(System.getProperty("user.dir"));
/** 开启 保存cglib生成的动态代理类类文件*/
try {
saveGeneratedCGlibProxyFiles(System.getProperty("user.dir"));
} catch (Exception e) {
e.printStackTrace();
}
//代理对象
SingStar proxy= (SingStar) new CglibProxyFactory(target).getProxyInstance();
proxy.sing();
}
public static void saveGeneratedCGlibProxyFiles(String dir) throws Exception {
Field field = System.class.getDeclaredField("props");
field.setAccessible(true);
Properties props = (Properties) field.get(null);
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, dir);//dir为保存文件路径
props.put("net.sf.cglib.core.DebuggingClassWriter.traceEnabled", "true");
}
}
cglib细节深入
invoke()和invokeSuper()区别
执行代理之前,Enhancer会通过creat()方法生成代理类【目标类(SingStar)的子类。经过增强的,它反编译后是extends目标类】SingStar$$EnhancerByCGLIB$$f7ff98ef.class
字节码。在调用目标类的sing()方法时会生成两个FastClass字节码文件(这也是Cglib调用方法效率高于原生Jdk代理的原因,Fast文件会把各个方法哈希码转换为类似数组下标的Index,方法调用时直接找对应的“下标”,不需要反射调用。)
1.SingStar$$EnhancerByCGLIB$$f7ff98ef$$FastClassByCGLIB$$a7574022.class
(代理类的FastClass,实例对象是fci.f2)
2SingStar$$FastClassByCGLIB$$a2922115.class
(目标类的FastClass 实例对象是fci.f1)
引用不同调的方法也不同,下面是intercept中4种调用方法本质
methodProxy.invokeSuper(target,args)
代理工厂的①methodProxy.invokeSuper(target,args)会报转型异常
由图可知调用MethodProxy的invokeSuper。
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
最终调用fci.f2.invoke(fci.i2, obj, args),即我们需要看代理类子类的FastClass(SingStar$$EnhancerByCGLIB$$f7ff98ef$$FastClassByCGLIB$$a7574022
)反编译后的java文件中的invoke方法:
public Object invoke(final int n, final Object o, final Object[] array) throws InvocationTargetException {
final SingStar$$EnhancerByCGLIB$$f7ff98ef singStar$$EnhancerByCGLIB$$f7ff98ef = (SingStar$$EnhancerByCGLIB$$f7ff98ef)o;
...
}
方法参数传入的o,是target(父类),要转型为代理类:SingStar$$EnhancerByCGLIB$$f7ff98ef
,而代理类是SingStar通过Enhancer 的creat方法创建的增强类(extends了目标类),也就是父类的扩展(子类),这样的向下转型肯定是不安全的,因为子类有的属性父类没有,java会自动检查抛出转型异常,关于向下转型可以参考Thinking in java这里不再赘述。
methodProxy.invokeSuper(obj,args)
③methodProxy.invokeSuper(obj,args);这是cglib提倡使用的方法。看看它的机制。
这里还有final int n
public int getIndex(final Signature signature) {
final String string = signature.toString();
switch (string.hashCode()) {
case -1985748682: {
//子类重写的sing方法下标21,hashCode和操作系统运算机制有关,不同的jdk生成的不一样。
if (string.equals("CGLIB$sing$1()V")) {
return 21;
}
break;
}
同样的再看fci.f2的invoke方法
public Object invoke(final int n, final Object o, final Object[] array) throws InvocationTargetException {
final SingStar$$EnhancerByCGLIB$$f7ff98ef singStar$$EnhancerByCGLIB$$f7ff98ef = (SingStar$$EnhancerByCGLIB$$f7ff98ef)o;
try {
switch (n) {
case 21: {
singStar$$EnhancerByCGLIB$$f7ff98ef.CGLIB$sing$1();
return null;
}
catch (Throwable t) {
throw new InvocationTargetException(t);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
好了看看singStar$$EnhancerByCGLIB$$f7ff98ef.CGLIB$sing$1()
:
final void CGLIB$sing$1() {
super.sing();
}
调用了目标类方法,没有疑问。
methodProxy.invoke(target,args)
②methodProxy.invoke(target,args);由图可知调用MethodProxy的invoke:
//recursion will result if you use the object passed as the first argument to the MethodInterceptor (usually not what you want)
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (IllegalArgumentException e) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw e;
}
}
走的是fci.f1.invoke(fci.i1, obj, args),看看fci.f1的fastCalss:
先看final int n
public int getIndex(final Signature signature) {
final String string = signature.toString();
switch (string.hashCode()) {
case 2094464646: {
//父类sing方法
if (string.equals("sing()V")) {
return 1;
}
break;
}
}
return -1;
}
fci.f1的invoke方法:
public Object invoke(final int n, final Object o, final Object[] array) throws InvocationTargetException {
final SingStar singStar = (SingStar)o;
try {
switch (n) {
case 0: {
return new Boolean(singStar.test((String)array[0]));
}
case 1: {
singStar.sing();
return null;
}
case 2: {
return new Boolean(singStar.equals(array[0]));
}
case 3: {
return singStar.toString();
}
case 4: {
return new Integer(singStar.hashCode());
}
}
}
catch (Throwable t) {
throw new InvocationTargetException(t);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
直接根据下标调用的singStar.sing()。此时的singStar是传入的父类对象target。直接调用目标类的方法。没有问题。但没有增强。
method.invoke(target,args)
method.invoke(target,args)由图看出调用的是jdk原生invoke方法,通过反射调用目标类方法,没问题。但这效率低下。
methodProxy.invoke(obj,args)
③methodProxy.invoke(obj,args);//发生循环调用,内存溢出。看一下步骤:
- 一开始 proxy.sing(),调用代理类sing(),
SingStar$$EnhancerByCGLIB$$f7ff98ef.class
的sing(),不是fci所以不会调fastclass里的方法。看CGLIB$BIND_CALLBACKS
方法,CGLIB$CALLBACK_0
,其实就是MethodIntercepter的对象,enhancer.setCallback(this)时传入的拦截器对象,我们设置了而且不为空。所以sing中走cglib$CALLBACK_0 != null逻辑,调用intercept
public final void sing() {
MethodInterceptor cglib$CALLBACK_2;
MethodInterceptor cglib$CALLBACK_0;
if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
CGLIB$BIND_CALLBACKS(this);
cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
}
//拦截器对象设置了不为null
if (cglib$CALLBACK_0 != null) {
cglib$CALLBACK_2.intercept((Object)this, SingStar$$EnhancerByCGLIB$$f7ff98ef.CGLIB$sing$1$Method, SingStar$$EnhancerByCGLIB$$f7ff98ef.CGLIB$emptyArgs, SingStar$$EnhancerByCGLIB$$f7ff98ef.CGLIB$sing$1$Proxy);
return;
}
super.sing();
}
/**cglib$CALLBACK_0是这么来的:最后一句也就是CGLIB$CALLBACK_0其实就是
MethodIntercepter的对象,enhancer.setCallback(this)时传入的拦截器对象,我们设
置了而且不为空。所以sing中走cglib$CALLBACK_0 != null逻辑
*/
private static final void CGLIB$BIND_CALLBACKS(final Object o) {
final SingStar$$EnhancerByCGLIB$$f7ff98ef singStar$$EnhancerByCGLIB$$f7ff98ef = (SingStar$$EnhancerByCGLIB$$f7ff98ef)o;
if (!singStar$$EnhancerByCGLIB$$f7ff98ef.CGLIB$BOUND) {
singStar$$EnhancerByCGLIB$$f7ff98ef.CGLIB$BOUND = true;
Object o2;
if ((o2 = SingStar$$EnhancerByCGLIB$$f7ff98ef.CGLIB$THREAD_CALLBACKS.get()) != null || (o2 = SingStar$$EnhancerByCGLIB$$f7ff98ef.CGLIB$STATIC_CALLBACKS) != null) {
singStar$$EnhancerByCGLIB$$f7ff98ef.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])o2)[0];
}
}
}
- 拦截器intercept中我们调用了MethodProxy的invoke(obj,args)。从fci.f1的fastCalss获取final int n=1,然后走
fci.f1.invoke(fci.i1, obj, args)
,调用singStar.sing()。final SingStar singStar = (SingStar)o,代理类向上转型,所以实际调的是代理类的sing().及proxy.sing()。
又去走intercept方法了,然后再执行proxy.sing();进入死循环,最终爆栈。
代理和装饰者模式区别
代理针对对象访问控制,比如开门这个功能影响了房子使用中的很多领域,所以我们把开门这一动作抽象出来做为代理。装饰模式,房间缺少椅子,但它不影响房子这个对象的基本属性,我们给他增加椅子、电视等等,扩展房子功能,这两个模式关注点不同,代理关注的是对象访问控制,装饰关注扩展对象功能。
public interface Room{
//可以睡觉、洗澡、做饭
public void action();
}
public class SleepRoom implements Room{
@Override
public void action(){
sleep();
};
private void sleep(){
System.out.pringtln("我要睡觉了");
};
}
public class RoomProxy implements Room{
RoomProxy(Room room){
this.room = room;
}
//睡觉、洗澡、做饭。都需要事先开门。它影响了房间多处功能。
@Override
public void action(){
System.out.pringtln("门打开了,进入房间");
room.action();
}
}
//装饰房子
public interface Room{
public void decorator();
}
//房间放椅子
public class ChairOfRoom implements Room{
@Override
public void decorator(){
putChair();
}
//房间放椅子
private void putChair(){
System.out.pringtln("放了八把椅子");
};
}
//创建一个抽象装饰器
public abstract class RoomDecorator implements Room{
protected Room decoratedRoom;
public RoomDecorator(Room decoratedRoom){
this.decoratedRoom= decoratedRoom;
}
public void decorator(){
decoratedRoom.decorator();
}
}
//实际椅子装饰器。
public class ChairDecorator extends RoomDecorator {
public ChairDecorator (Room decoratedRoom) {
super(decoratedRoom);
}
@Override
public void decorator() {
decoratedRoom.decorator();
}
}