美文网首页
Spring-@Lookup

Spring-@Lookup

作者: AlanSun2 | 来源:发表于2019-08-29 13:43 被阅读0次

当一个singleton中需要注入prototype类型时,你有三种方法来处理:

  1. 实现ApplicationContextAware每次都显示的获取prototype实例,如下:
@Service
public abstract class MyJavaBean  {
    @Autowired
    private ApplicationContext applicationContext;

    public String print() {
        applicationContext.getBean("ttt");
        return "sdf";
    }
}
  1. 查找方法注入:@Lookup
public abstract class MyJavaBean {

    public String print() {
        Depend de = getDe();
        de.print();
        return "sdf";
    }

    @Lookup
    abstract Depend getDe();
}

这种方法Spring会生成该bean时判断是否有methodOverride使用cglib生成一个MyJavaBean的子类,如下图:
SimpleInstantiationStrategy -> instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)

@Override
    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
        // Don't override the class with CGLIB if no overrides.
                //判断bean定义中是否有methodOverride
        if (!bd.hasMethodOverrides()) {
            Constructor<?> constructorToUse;
            synchronized (bd.constructorArgumentLock) {
                constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
                if (constructorToUse == null) {
                    final Class<?> clazz = bd.getBeanClass();
                    if (clazz.isInterface()) {
                        throw new BeanInstantiationException(clazz, "Specified class is an interface");
                    }
                    try {
                        if (System.getSecurityManager() != null) {
                            constructorToUse = AccessController.doPrivileged(
                                    (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                        }
                        else {
                            constructorToUse = clazz.getDeclaredConstructor();
                        }
                        bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                    }
                    catch (Throwable ex) {
                        throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                    }
                }
            }
            return BeanUtils.instantiateClass(constructorToUse);
        }
        else {
            // Must generate CGLIB subclass.
            return instantiateWithMethodInjection(bd, beanName, owner);
        }
    }

子类会实现@Lookup标记的方法,当调用getDe方法时,Spring调用的子类方法,如下图:

@lookup.png

对应的字节码文件:

public class MyJavaBean$$EnhancerBySpringCGLIB$$a9b28364 extends MyJavaBean implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private NoOp CGLIB$CALLBACK_0;
    private MethodInterceptor CGLIB$CALLBACK_1;
    private MethodInterceptor CGLIB$CALLBACK_2;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$getDe$1$Method;
    private static final MethodProxy CGLIB$getDe$1$Proxy;
    private static final Object[] CGLIB$emptyArgs;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.alan344.demo.day4.MyJavaBean$$EnhancerBySpringCGLIB$$a9b28364");
        Class var1;
        CGLIB$getDe$1$Method = ReflectUtils.findMethods(new String[]{"getDe", "()Lcom/alan344/demo/day4/Depend;"}, (var1 = Class.forName("com.alan344.demo.day4.MyJavaBean")).getDeclaredMethods())[0];
        CGLIB$getDe$1$Proxy = MethodProxy.create(var1, var0, "()Lcom/alan344/demo/day4/Depend;", "getDe", "CGLIB$getDe$1");
    }

    final Depend CGLIB$getDe$1() {
        return super.getDe();
    }
    //对应的子类方法
    final Depend getDe() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
        if (this.CGLIB$CALLBACK_1 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_1;
        }

        return var10000 != null ? (Depend)var10000.intercept(this, CGLIB$getDe$1$Method, CGLIB$emptyArgs, CGLIB$getDe$1$Proxy) : super.getDe();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case 1184742670:
            if (var10000.equals("getDe()Lcom/alan344/demo/day4/Depend;")) {
                return CGLIB$getDe$1$Proxy;
            }
        }

        return null;
    }

    public MyJavaBean$$EnhancerBySpringCGLIB$$a9b28364() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        MyJavaBean$$EnhancerBySpringCGLIB$$a9b28364 var1 = (MyJavaBean$$EnhancerBySpringCGLIB$$a9b28364)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (CGLIB$STATIC_CALLBACKS == null) {
                    return;
                }
            }

            Callback[] var10001 = (Callback[])var10000;
            var1.CGLIB$CALLBACK_2 = (MethodInterceptor)((Callback[])var10000)[2];
            var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];
            var1.CGLIB$CALLBACK_0 = (NoOp)var10001[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        MyJavaBean$$EnhancerBySpringCGLIB$$a9b28364 var10000 = new MyJavaBean$$EnhancerBySpringCGLIB$$a9b28364();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        throw new IllegalStateException("More than one callback object required");
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        MyJavaBean$$EnhancerBySpringCGLIB$$a9b28364 var10000 = new MyJavaBean$$EnhancerBySpringCGLIB$$a9b28364;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        Object var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        case 1:
            var10000 = this.CGLIB$CALLBACK_1;
            break;
        case 2:
            var10000 = this.CGLIB$CALLBACK_2;
            break;
        default:
            var10000 = null;
        }

        return (Callback)var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (NoOp)var2;
            break;
        case 1:
            this.CGLIB$CALLBACK_1 = (MethodInterceptor)var2;
            break;
        case 2:
            this.CGLIB$CALLBACK_2 = (MethodInterceptor)var2;
        }

    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0, this.CGLIB$CALLBACK_1, this.CGLIB$CALLBACK_2};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (NoOp)var1[0];
        this.CGLIB$CALLBACK_1 = (MethodInterceptor)var1[1];
        this.CGLIB$CALLBACK_2 = (MethodInterceptor)var1[2];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

这里的MethodInterceptor CGLIB$CALLBACK_1LookupOverrideMethodInterceptor。这里会调用LookupOverrideMethodInterceptor #intercept方法。

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
            // Cast is safe, as CallbackFilter filters are used selectively.
            LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
            Assert.state(lo != null, "LookupOverride not found");
            Object[] argsToUse = (args.length > 0 ? args : null);  // if no-arg, don't insist on args at all
            if (StringUtils.hasText(lo.getBeanName())) {
                return (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
                        this.owner.getBean(lo.getBeanName()));
            }
            else {
//获取原型bean
                return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
                        this.owner.getBean(method.getReturnType()));
            }
        }
  1. 任意方法替换
    与查找方法注入相比,一种不太有用的方法注入形式。不做介绍

相关文章

  • Spring-@Lookup

    当一个singleton中需要注入prototype类型时,你有三种方法来处理: 实现ApplicationCon...

网友评论

      本文标题:Spring-@Lookup

      本文链接:https://www.haomeiwen.com/subject/zgibectx.html