当一个singleton
中需要注入prototype
类型时,你有三种方法来处理:
- 实现
ApplicationContextAware
每次都显示的获取prototype
实例,如下:
@Service
public abstract class MyJavaBean {
@Autowired
private ApplicationContext applicationContext;
public String print() {
applicationContext.getBean("ttt");
return "sdf";
}
}
- 查找方法注入:@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调用的子类方法,如下图:
![](https://img.haomeiwen.com/i5614480/a4fe822538e1086c.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_1
是LookupOverrideMethodInterceptor
。这里会调用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()));
}
}
- 任意方法替换
与查找方法注入相比,一种不太有用的方法注入形式。不做介绍
网友评论