Spring-Aop原理

AOP 面向切面编程#

Aop是什么#

  • 与OOP对比,传统的OOP开发中的代码逻辑是自上而下的,而这些过程会产生一些横切性问题,这些横切性的问题和我们的主业务逻辑关系不大,这些横切性问题不会影响到主逻辑实现的,但是会散落到代码的各个部分,难以维护。
  • AOP是处理一些横切性问题,AOP的编程思想就是把这些问题和主业务逻辑分开,达到与主业务逻辑解耦的目的。使代码的重用性和开发效率更高。
  • AspectJ AOP是一个AOP实现,同样还有Jboos AopSpring AOP实现。
  • 虽然spring本身有springAop实现,但是它的语法太复杂,所以它继承了aspectJ的语法来表现springAop。(使用了aspectJ注解而已,运行时仍然是纯Spring AOP,并且不依赖于AspectJ编译器或编织器。)
  • springAOP是动态织入,也就是运行时织入的。AspectJ是静态织入,编译的时候就织入进去代码了。

aop的应用场景#

日志记录、权限验证、效率检查、事务管理、分布式锁、exception…

概念(spring官网)#

  • target 目标对象,就是aop增强前的原始对象
  • aop Proxy 代理对象,包含了原始对象的代码和增加后的代码的增强后的对象。(类比装饰模式)
  • Joinpoint:连接点目标对象中的方法。springAOP中最小的AOP单元是连接点,也就是方法。一系列连接点的集合称为切点PointCut。 ----------------> (要关注和增强的方法,也就是我们要作用的点)
  • pointcut:切点表示连接点的集合 -------------------> (是告诉通知连接点在哪里,切点表达式决定 JoinPoint 的数量)
  • Advice:通知,通知到哪里去,通知什么逻辑。 (位置 + logic),一般是拦截器实现。
    • advice通知类型:
      • Before 连接点执行之前,但是无法阻止连接点的正常执行,除非该段执行抛出异常
      • After 连接点正常执行之后,执行过程中正常执行返回退出,非异常退出
      • After throwing 执行抛出异常的时候
      • After (finally) 无论连接点是正常退出还是异常退出,都会执行
      • Around advice: 围绕连接点执行,例如方法调用。这是最有用的切面方式。around通知可以在方法调用之前和之后执行自定义行为。它还负责选择是继续加入点还是通过返回自己的返回值或抛出异常来快速建议的方法执行。
  • Aspect: 切面:切点、连接点、通知的一个载体。就是对连接点、通知的逻辑要写到哪里去的一个地方。(aspectJ实现的话是一个类,spring的话是一个xml标签)一定要给spring去管理,是一个抽象。
  • Weaving :把代理逻辑加入到目标对象方法上的过程叫做织入。将Aspect切面与其他Class或对象链接以创建Advice的对象的过程。 这可以在编译时(例如,使用AspectJ编译器),加载时或在运行时完成。 Spring AOP在运行时执行编织
  • Proceedingjoinpoint 和JoinPoint的区别:

Proceedingjoinpoint 继承了JoinPoint,proceed()这个是aop代理链执行的方法。并扩充实现了proceed()方法,用于继续执行连接点。JoinPoint仅能获取相关参数,无法执行连接点。

  • JoinPoint的方法
  1. java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;
  2. Signature getSignature() :获取连接点的方法签名对象;
  3. java.lang.Object getTarget() :获取连接点所在的目标对象;
  4. java.lang.Object getThis() :获取代理对象本身;

proceed()有重载,有个带参数的方法,可以修改目标方法的的参数

Introductions

perthis

使用方式如下:

@Aspect(“perthis(this(com.chenss.dao.IndexDaoImpl))”)

要求:

\1. AspectJ对象的注入类型为prototype

\2. 目标对象也必须是prototype的

原因为:只有目标对象是原型模式的,每次getBean得到的对象才是不一样的,由此针对每个对象就会产生新的切面对象,才能产生不同的切面结果。

Spring实现#

  • 默认使用JDK动态代理实现(但是需要接口),也可以使用CGlib实现。

  • 开启AspectJ支持,两种方式:

    • 首先引入aspectjweaver.jar

    • xml方式: <aop:aspectj-autoproxy/>

    • 或者javaconfig方式:

    • @Configuration
      @EnableAspectJAutoProxy
      public class AppConfig {
      
      }
      <!--code0-->
      
      
  • Aspect(也就是上面用@Aspect注释的类)可以有方法和字段,还可以包含切入点joinPoint、Advice通知和introduction(inter-type)声明。

  • Aspect本身不能被其他的Aspect进行增强

声明一个Pointcut切入点的方式:#

切入点确定了感兴趣的连接点(也就是PointCut是一系列JoinPoint的集合),从而使我们能够控制执行通知Advice的时间。 Spring AOP仅支持Spring Bean的方法执行连接点,因此可以将**PointCut视为Spring Bean上的方法执行**。

  • 切入点声明由两部分组成:一个包含名称和任何参数的签名,以及一个切入点表达式,该切入点表达式准确确定我们感兴趣的方法执行。在AOP的@AspectJ批注样式中,常规方法定义提供了切入点签名。 并使用@Pointcut批注指示切入点表达式(用作切入点签名的方法必须具有void返回类型),一般是一个空方法。

切入点表达式:#

  • execution: For matching method execution join points.匹配方法的表达式,最齐全,是springAOP最重要的匹配符。

    • 下面是execution的一个完整的各部分含义,带的是可选的,也就是可以省略的

    • execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

    • 其中各项的语义如下

      • modifiers-pattern:方法的可见性,如public,protected;不可是*,可以省略。

      • ret-type-pattern:方法的返回值类型,如int,void等;

      • declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;

      • name-pattern:方法名类型,如buisinessService();

      • param-pattern:方法的参数类型,如java.lang.String;

      • throws-pattern:方法抛出的异常类型,如java.lang.Exception;

    • // 案例
      @Pointcut("execution(* com.sam.dao.*.*(..))")//匹配com.sam.dao包下的任意接口和类的任意方法
      @Pointcut("execution(public * com.sam.dao.*.*(..))")//匹配com.sam.dao包下的任意接口和类的public方法
      @Pointcut("execution(public * com.sam.dao.*.*())")//匹配com.sam.dao包下的任意接口和类的public 无方法参数的方法
      @Pointcut("execution(* com.sam.dao.*.*(java.lang.String, ..))")//匹配com.sam.dao包下的任意接口和类的第一个参数为String类型的方法
      @Pointcut("execution(* com.sam.dao.*.*(java.lang.String))")//匹配com.sam.dao包下的任意接口和类的只有一个参数,且参数为String类型的方法
      @Pointcut("execution(* com.sam.dao.*.*(java.lang.String))")//匹配com.sam.dao包下的任意接口和类的只有一个参数,且参数为String类型的方法
      @Pointcut("execution(public * *(..))")//匹配任意的public方法
      @Pointcut("execution(* query*(..))")//匹配任意的以query开头的方法
      @Pointcut("execution(* com.sam.dao.IndexDao.*(..))")//匹配com.sam.dao.IndexDao接口中任意的方法
      @Pointcut("execution(* com.sam.dao..*.*(..))")//匹配com.sam.dao包及其子包中任意的方法
      
      <!--code1-->
      
      

测试introduction引入机制:

1
2
3
4
5
6
7
8
9
System.out.println("================================introduction==============");
ICBCService icbcService = context.getBean(ICBCService.class);
// 原生ICBCService这个类,没有任何接口,只是有一个otherMethod方法
icbcService.otherMethod("param");
// ICBCService 没有实现UserBankService接口,但是可以强转为UserBankService,因为AOP使用了introduction为他引入了UserBankService接口的实现:UserServiceImpl
UserBankService icbcBankService = (UserBankService) icbcService;
// 所以此处调用是UserServiceImpl的逻辑
icbcBankService.addMoney("lisi",300);
System.out.println("\n================================introduction==============");
  • within: Limits matching to join points within certain types。限定于某些方法内的匹配符表达式。

    • @After("within(com.sam.bootdemo.service.impl.UserServiceImpl)") // UserServiceImpl类的所有方法
      <!--code3-->
      
      
  • args:限制参数类型,如:

    • @Pointcut("args(java.lang.String)")  //匹配一个String类型的参数,也常常组合使用
      <!--code4-->
      
      
  • introduction:引入,给一个Bean引入一个接口的实现。使得这个Bean可以当作另外一个接口的实现类使用。

AOP的实现#

先看一个现象:

1
2
3
// spring.aop.proxy-target-class= false 时候是JDK动态代理。和UserBankServiceImpl同样接口、具有相同行为,但是不是UserBankServiceImpl,所以下面是false
// spring.aop.proxy-target-class= true 时候是CGlib继承。行为和类型都相同,下面是true
System.out.println(bankService instanceof UserBankServiceImpl);

代理的结果默认JDK动态代理通过接口实现,不等于我们的目标对象。

声明式事务#

上面讲的只是AOP,只能在方法之前之后进行增强,无法在方法代码内部进行插入增强。需要这么做只能advisor实现。

但是advisor@AspectJ Support中不能支持,可以使用XML进行实现。非要在Java中实现只能更换一种方式:

待续…

SpringAOP的原理#

这里先看一个Spring对@Configuration的代理实现:

这部分是在invokeBeanFactoryPostProceccer方法中,由ConfigurationClassPostProcessor在扫描到full@Configuration修饰类后调用ConfigurationClassEnhancer#enhance(claz,clazLoader)进行封装的:

核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

/*
* CHlib创建子类的核心逻辑
* Creates a new CGLIB {@link Enhancer} instance.
*/
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
// 一个增强器,是CGlib核心接口ClassGenerator的实现
Enhancer enhancer = new Enhancer();
// 设置父类,就是当前@Configuration修饰的类
enhancer.setSuperclass(configSuperClass);
// 给代理类实现一个实际上是BeanFactoryAware接口,用来注入$$beanFactory
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
// 是否实现Factory接口,一般false
enhancer.setUseFactory(false);
// 生成的beanName策略 xxxBySpringCGLIB
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
// 自定义CGlib生成策略,里面声明了一个public 的 $$beanFactory用来存放aware注入的bf
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
// 设置一个方法调用的过滤器,塞进去了两个:
//new BeanMethodInterceptor():
//拦截@Bean方法,&beanName去BF里面拿一下,判断是否是FactoryBean,是的话对FB里面的getObject进行代理,非inCreation调用时返回引用。容器调用的时候inCreation,才真的getObject
// 非FactoryBean的代理了@Bean注解方法,非inCreation调用时返回引用。容器调用的时候inCreation,才真的new
//new BeanFactoryAwareMethodInterceptor(),
// 代理setBF方法,如果找到$$beanFactory,就在setBF方法里面给bf设置到$$beanFactory上
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}

完整spring代理CGlib的过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
package org.springframework.context.annotation;


/**
* 这个类使用CGlib来生成@Configuration类的子类,使得每一个@Bean修饰的方法都会被子类重写,除非容器来调用,否则在其他地方来调用这些@Bean方法的时候不会创建对象(会破坏单例性),而是返回一个容器内已有的Bean的引用。
* Enhances {@link Configuration} classes by generating a CGLIB subclass which
* interacts with the Spring container to respect bean scoping semantics for
* {@code @Bean} methods. Each such {@code @Bean} method will be overridden in
* the generated subclass, only delegating to the actual {@code @Bean} method
* implementation if the container actually requests the construction of a new
* instance. Otherwise, a call to such an {@code @Bean} method serves as a
* reference back to the container, obtaining the corresponding bean by name.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.0
* @see #enhance
* @see ConfigurationClassPostProcessor
*/
class ConfigurationClassEnhancer {

// The callbacks to use. Note that these callbacks must be stateless.
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};

private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);

// 子类里面增强一个BF的属性
private static final String BEAN_FACTORY_FIELD = "$$beanFactory";


private static final Log logger = LogFactory.getLog(ConfigurationClassEnhancer.class);

private static final SpringObjenesis objenesis = new SpringObjenesis();


/**
外面ConfigurationClassPostProcessor调用的入口
* Loads the specified class and generates a CGLIB subclass of it equipped with
* container-aware callbacks capable of respecting scoping and other bean semantics.
* @return the enhanced subclass
*/
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) { // 这里判断是否EnhancedConfiguration接口。这是一个空接口,是BFAware的子接口,
if (logger.isDebugEnabled()) {
logger.debug(String.format("Ignoring request to enhance %s as it has " +
"already been enhanced. This usually indicates that more than one " +
"ConfigurationClassPostProcessor has been registered (e.g. via " +
"<context:annotation-config>). This is harmless, but you may " +
"want check your configuration and remove one CCPP if possible",
configClass.getName()));
}
return configClass;
}
// 否则,真正开始进行增强
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
if (logger.isTraceEnabled()) {
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
configClass.getName(), enhancedClass.getName()));
}
return enhancedClass;
}

/*
* CGlib创建子类的核心逻辑
* Creates a new CGLIB {@link Enhancer} instance.
*/
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
// 一个增强器,是CGlib核心接口ClassGenerator的实现
Enhancer enhancer = new Enhancer();
// 设置父类,就是当前@Configuration修饰的类
enhancer.setSuperclass(configSuperClass);
// 给代理类实现一个实际上是BeanFactoryAware接口,用来注入$$beanFactory
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
// 是否实现Factory接口,一般false
enhancer.setUseFactory(false);
// 生成的beanName策略 xxxBySpringCGLIB
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
// 自定义CGlib生成策略,里面声明了一个public 的 $$beanFactory用来存放aware注入的bf
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
// 设置一个方法调用的过滤器,塞进去了两个:
//new BeanMethodInterceptor():
//拦截@Bean方法,&beanName去BF里面拿一下,判断是否是FactoryBean,是的话对FB里面的getObject进行代理,非inCreation调用时返回引用。容器调用的时候inCreation,才真的getObject
// 非FactoryBean的代理了@Bean注解方法,非inCreation调用时返回引用。容器调用的时候inCreation,才真的new
//new BeanFactoryAwareMethodInterceptor(),
// 代理setBF方法,如果找到$$beanFactory,就在setBF方法里面给bf设置到$$beanFactory上
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}

/**
* Uses enhancer to generate a subclass of superclass,
* ensuring that callbacks are registered for the new subclass.
*/
private Class<?> createClass(Enhancer enhancer) {
Class<?> subclass = enhancer.createClass();
// Registering callbacks statically (as opposed to thread-local)
// is critical for usage in an OSGi environment (SPR-5932)...
Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
return subclass;
}


/**
空接口,只是一个BFAware的子接口,用来标记当前类可以注入BF
* Marker interface to be implemented by all @Configuration CGLIB subclasses.
* Facilitates idempotent behavior for {@link ConfigurationClassEnhancer#enhance}
* through checking to see if candidate classes are already assignable to it, e.g.
* have already been enhanced.
* <p>Also extends {@link BeanFactoryAware}, as all enhanced {@code @Configuration}
* classes require access to the {@link BeanFactory} that created them.
* <p>Note that this interface is intended for framework-internal use only, however
* must remain public in order to allow access to subclasses generated from other
* packages (i.e. user code).
*/
public interface EnhancedConfiguration extends BeanFactoryAware {
}


/**
* Conditional {@link Callback}.
* @see ConditionalCallbackFilter
*/
private interface ConditionalCallback extends Callback {

boolean isMatch(Method candidateMethod);
}


/**
* A {@link CallbackFilter} that works by interrogating {@link Callback Callbacks} in the order
* that they are defined via {@link ConditionalCallback}.
*/
private static class ConditionalCallbackFilter implements CallbackFilter {

private final Callback[] callbacks;

private final Class<?>[] callbackTypes;

public ConditionalCallbackFilter(Callback[] callbacks) {
this.callbacks = callbacks;
this.callbackTypes = new Class<?>[callbacks.length];
for (int i = 0; i < callbacks.length; i++) {
this.callbackTypes[i] = callbacks[i].getClass();
}
}

@Override
public int accept(Method method) {
for (int i = 0; i < this.callbacks.length; i++) {
Callback callback = this.callbacks[i];
if (!(callback instanceof ConditionalCallback) || ((ConditionalCallback) callback).isMatch(method)) {
return i;
}
}
throw new IllegalStateException("No callback available for method " + method.getName());
}

public Class<?>[] getCallbackTypes() {
return this.callbackTypes;
}
}


/**
* Custom extension of CGLIB's DefaultGeneratorStrategy, introducing a {@link BeanFactory} field.
* Also exposes the application ClassLoader as thread context ClassLoader for the time of
* class generation (in order for ASM to pick it up when doing common superclass resolution).
*/
private static class BeanFactoryAwareGeneratorStrategy extends
ClassLoaderAwareGeneratorStrategy {

public BeanFactoryAwareGeneratorStrategy(@Nullable ClassLoader classLoader) {
super(classLoader);
}

@Override
protected ClassGenerator transform(ClassGenerator cg) throws Exception {
ClassEmitterTransformer transformer = new ClassEmitterTransformer() {
@Override
public void end_class() {
// 给代理类塞进去一个public的$$beanFactory属性,用来BeanFactoryAware接口的setBF的时候拦截注入BF
declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null);
super.end_class();
}
};
return new TransformingClassGenerator(cg, transformer);
}

}


/**
* Intercepts the invocation of any {@link BeanFactoryAware#setBeanFactory(BeanFactory)} on
* {@code @Configuration} class instances for the purpose of recording the {@link BeanFactory}.
* @see EnhancedConfiguration
*/
private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback {

@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
Assert.state(field != null, "Unable to find generated BeanFactory field");
field.set(obj, args[0]);

// Does the actual (non-CGLIB) superclass implement BeanFactoryAware?
// If so, call its setBeanFactory() method. If not, just exit.
if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
return proxy.invokeSuper(obj, args);
}
return null;
}

@Override
public boolean isMatch(Method candidateMethod) {
// 匹配是否是setBeanFactory方法
return isSetBeanFactory(candidateMethod);
}

public static boolean isSetBeanFactory(Method candidateMethod) {
return (candidateMethod.getName().equals("setBeanFactory") &&
candidateMethod.getParameterCount() == 1 &&
BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
}
}


/**
* Intercepts the invocation of any {@link Bean}-annotated methods in order to ensure proper
* handling of bean semantics such as scoping and AOP proxying.
* @see Bean
* @see ConfigurationClassEnhancer
*/
private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {

/**
* Enhance a {@link Bean @Bean} method to check the supplied BeanFactory for the
* existence of this bean object.
* @throws Throwable as a catch-all for any exception that may be thrown when invoking the
* super implementation of the proxied method i.e., the actual {@code @Bean} method
*/
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {

ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

// Determine whether this bean is a scoped-proxy
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}

// To handle the case of an inter-bean method reference, we must explicitly check the
// container for already cached instances.

// 首先检查是不是FactoryBean,是的话就创建一个子类并拦截getObject()方法,调用缓存的对象。
// First, check to see if the requested bean is a FactoryBean. If so, create a subclass
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// This ensures that the semantics of calling a FactoryBean from within @Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
// 如果是一个FactoryBean,而且&beanName可以拿到,就去处理FactoryBean
if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
factoryContainsBean(beanFactory, beanName)) {
Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// Scoped proxy factory beans are a special case and should not be further proxied
}
else {
// It is a candidate FactoryBean - go ahead with enhancement
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}

// BF在调用的时候,需要真的去创建
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
// The factory is calling the bean method in order to instantiate and register the bean
// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
// create the bean instance.
if (logger.isInfoEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
"result in a failure to process annotations such as @Autowired, " +
"@Resource and @PostConstruct within the method's declaring " +
"@Configuration class. Add the 'static' modifier to this method to avoid " +
"these container lifecycle issues; see @Bean javadoc for complete details.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
}
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}

return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

// 拿到bean的引用
private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
ConfigurableBeanFactory beanFactory, String beanName) {

// The user (i.e. not the factory) is requesting this bean through a call to
// the bean method, direct or indirect. The bean may have already been marked
// as 'in creation' in certain autowiring scenarios; if so, temporarily set
// the in-creation status to false in order to avoid an exception.
boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
try {
if (alreadyInCreation) {
beanFactory.setCurrentlyInCreation(beanName, false);
}
boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
if (useArgs && beanFactory.isSingleton(beanName)) {
// Stubbed null arguments just for reference purposes,
// expecting them to be autowired for regular singleton references?
// A safe assumption since @Bean singleton arguments cannot be optional...
for (Object arg : beanMethodArgs) {
if (arg == null) {
useArgs = false;
break;
}
}
}
Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
beanFactory.getBean(beanName));
if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
// Detect package-protected NullBean instance through equals(null) check
if (beanInstance.equals(null)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("@Bean method %s.%s called as bean reference " +
"for type [%s] returned null bean; resolving to null value.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
beanMethod.getReturnType().getName()));
}
beanInstance = null;
}
else {
String msg = String.format("@Bean method %s.%s called as bean reference " +
"for type [%s] but overridden by non-compatible bean instance of type [%s].",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
try {
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore - simply no detailed message then.
}
throw new IllegalStateException(msg);
}
}
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
if (currentlyInvoked != null) {
String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
beanFactory.registerDependentBean(beanName, outerBeanName);
}
return beanInstance;
}
finally {
if (alreadyInCreation) {
beanFactory.setCurrentlyInCreation(beanName, true);
}
}
}

@Override
public boolean isMatch(Method candidateMethod) {
return (candidateMethod.getDeclaringClass() != Object.class &&
!BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
}

private ConfigurableBeanFactory getBeanFactory(Object enhancedConfigInstance) {
Field field = ReflectionUtils.findField(enhancedConfigInstance.getClass(), BEAN_FACTORY_FIELD);
Assert.state(field != null, "Unable to find generated bean factory field");
Object beanFactory = ReflectionUtils.getField(field, enhancedConfigInstance);
Assert.state(beanFactory != null, "BeanFactory has not been injected into @Configuration class");
Assert.state(beanFactory instanceof ConfigurableBeanFactory,
"Injected BeanFactory is not a ConfigurableBeanFactory");
return (ConfigurableBeanFactory) beanFactory;
}

/**
* Check the BeanFactory to see whether the bean named <var>beanName</var> already
* exists. Accounts for the fact that the requested bean may be "in creation", i.e.:
* we're in the middle of servicing the initial request for this bean. From an enhanced
* factory method's perspective, this means that the bean does not actually yet exist,
* and that it is now our job to create it for the first time by executing the logic
* in the corresponding factory method.
* <p>Said another way, this check repurposes
* {@link ConfigurableBeanFactory#isCurrentlyInCreation(String)} to determine whether
* the container is calling this method or the user is calling this method.
* @param beanName name of bean to check for
* @return whether <var>beanName</var> already exists in the factory
*/
private boolean factoryContainsBean(ConfigurableBeanFactory beanFactory, String beanName) {
return (beanFactory.containsBean(beanName) && !beanFactory.isCurrentlyInCreation(beanName));
}

/**
* Check whether the given method corresponds to the container's currently invoked
* factory method. Compares method name and parameter types only in order to work
* around a potential problem with covariant return types (currently only known
* to happen on Groovy classes).
*/
private boolean isCurrentlyInvokedFactoryMethod(Method method) {
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}

/**
* Create a subclass proxy that intercepts calls to getObject(), delegating to the current BeanFactory
* instead of creating a new instance. These proxies are created only when calling a FactoryBean from
* within a Bean method, allowing for proper scoping semantics even when working against the FactoryBean
* instance directly. If a FactoryBean instance is fetched through the container via &-dereferencing,
* it will not be proxied. This too is aligned with the way XML configuration works.
*/
private Object enhanceFactoryBean(final Object factoryBean, Class<?> exposedType,
final ConfigurableBeanFactory beanFactory, final String beanName) {

try {
Class<?> clazz = factoryBean.getClass();
boolean finalClass = Modifier.isFinal(clazz.getModifiers());
boolean finalMethod = Modifier.isFinal(clazz.getMethod("getObject").getModifiers());
if (finalClass || finalMethod) {
if (exposedType.isInterface()) {
if (logger.isTraceEnabled()) {
logger.trace("Creating interface proxy for FactoryBean '" + beanName + "' of type [" +
clazz.getName() + "] for use within another @Bean method because its " +
(finalClass ? "implementation class" : "getObject() method") +
" is final: Otherwise a getObject() call would not be routed to the factory.");
}
return createInterfaceProxyForFactoryBean(factoryBean, exposedType, beanFactory, beanName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Unable to proxy FactoryBean '" + beanName + "' of type [" +
clazz.getName() + "] for use within another @Bean method because its " +
(finalClass ? "implementation class" : "getObject() method") +
" is final: A getObject() call will NOT be routed to the factory. " +
"Consider declaring the return type as a FactoryBean interface.");
}
return factoryBean;
}
}
}
catch (NoSuchMethodException ex) {
// No getObject() method -> shouldn't happen, but as long as nobody is trying to call it...
}

return createCglibProxyForFactoryBean(factoryBean, beanFactory, beanName);
}

private Object createInterfaceProxyForFactoryBean(final Object factoryBean, Class<?> interfaceType,
final ConfigurableBeanFactory beanFactory, final String beanName) {

return Proxy.newProxyInstance(
factoryBean.getClass().getClassLoader(), new Class<?>[] {interfaceType},
(proxy, method, args) -> {
if (method.getName().equals("getObject") && args == null) {
return beanFactory.getBean(beanName);
}
return ReflectionUtils.invokeMethod(method, factoryBean, args);
});
}

private Object createCglibProxyForFactoryBean(final Object factoryBean,
final ConfigurableBeanFactory beanFactory, final String beanName) {

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(factoryBean.getClass());
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setCallbackType(MethodInterceptor.class);

// Ideally create enhanced FactoryBean proxy without constructor side effects,
// analogous to AOP proxy creation in ObjenesisCglibAopProxy...
Class<?> fbClass = enhancer.createClass();
Object fbProxy = null;

if (objenesis.isWorthTrying()) {
try {
fbProxy = objenesis.newInstance(fbClass, enhancer.getUseCache());
}
catch (ObjenesisException ex) {
logger.debug("Unable to instantiate enhanced FactoryBean using Objenesis, " +
"falling back to regular construction", ex);
}
}

if (fbProxy == null) {
try {
fbProxy = ReflectionUtils.accessibleConstructor(fbClass).newInstance();
}
catch (Throwable ex) {
throw new IllegalStateException("Unable to instantiate enhanced FactoryBean using Objenesis, " +
"and regular FactoryBean instantiation via default constructor fails as well", ex);
}
}

((Factory) fbProxy).setCallback(0, (MethodInterceptor) (obj, method, args, proxy) -> {
if (method.getName().equals("getObject") && args.length == 0) {
return beanFactory.getBean(beanName);
}
return proxy.invoke(factoryBean, args);
});

return fbProxy;
}
}
}