前提
- Spring 5
- 基于Java Configuration配置,而非XML配置
- 非Web环境
@Bean的处理
与AOP构造器的创建过程类似(具体的可以查看这篇文章:多个AspectJ对同一个对象操作产生的实际效果以及顺序情况),@Bean
的处理也是在ConfigurationClassParser
类的doProcessConfigurationClass
方法内做的处理:
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
之后在ConfigurationClassPostProcessor
类的processConfigBeanDefinitions
方法内解析:
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
retrieveBeanMethodMetadata
方法,主要是为了获取@Bean
注解的方法的相关元数据,比如方法名、所在类全名、返回类型、是否静态、是否不可覆盖等等信息。
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
// 获取类的元数据
AnnotationMetadata original = sourceClass.getMetadata();
// 从元数据内获取注解有@Bean的方法集合
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
// 判断方法集合是否超过两个,并且类的元数据是StandardAnnotationMetadata实例,则从ASM内获取声明的方法顺序
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
// 尝试通过ASM从类文件判断方法的顺序...因为,JVM的标准反射库获取的方法顺序是随机的,甚至泡在相同JVM的不同应用返回的顺序也会不一致
try {
AnnotationMetadata asm =
this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
if (asmMethods.size() >= beanMethods.size()) {
Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
// 做了一遍过滤,将二进制class文件的方法与JVM反射的方法做一次对比,防止将非编程方法加入,保持与JVM反射获取方法一致,除了顺序。
for (MethodMetadata asmMethod : asmMethods) {
for (MethodMetadata beanMethod : beanMethods) {
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
selectedMethods.add(beanMethod);
break;
}
}
}
if (selectedMethods.size() == beanMethods.size()) {
// All reflection-detected methods found in ASM method set -> proceed
beanMethods = selectedMethods;
}
}
}
catch (IOException ex) {
logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
// No worries, let's continue with the reflection metadata we started with...
}
}
return beanMethods;
}
在loadBeanDefinitions
方法内,调用了loadBeanDefinitionsForConfigurationClass
来注册Config Bean本身、内部声明的@Bean
方法、@Import
和@ImportResource
相关的Bean信息。这里具体查看注册@Bean
的过程:
// 循环所有注解有@Bean的方法,并调用loadBeanDefinitionsForBeanMethod方法注册
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsForBeanMethod
方法主要是做了别名注册,注解声明的类定义注册以及@Scope
注解的代理类覆盖的工作:
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
// 获取配置类以及注解方法的相关信息
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
// 判断是否需要跳过这个类
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
// 如果这个类被跳过,则直接返回
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
// 提取@Bean注解的属性
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
// 不存在@Bean,则抛出异常
Assert.state(bean != null, "No @Bean annotation attributes");
// 获取@Bean注册的别名
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// 注册所有的别名
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
// 是否允许覆盖已存在的定义(判断依据来自isOverriddenByExistingDefinition方法,这里不做展开)
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
"' clashes with bean name for containing configuration class; please make those names unique!");
}
return;
}
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(methodName);
}
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
// Scope的代理信息获取
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getString("value"));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
// 如果存在Scope代理,则使用代理类定义覆盖原有的类定义
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
}
if (logger.isDebugEnabled()) {
logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",
configClass.getMetadata().getClassName(), beanName));
}
// 注册类定义
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
之后通过Bean工厂,调用preInstantiateSingletons
方法,与初始化Bean的单例。在这个过程中,同样将@Bean
标注的类构建方法初始化了。与其他类的初始化不同的是,标注有@Bean
的类构造方法的初始化,是通过factoryMethodName
来进行的(具体查看的AbstractAutowireCapableBeanFactory
类的createBeanInstance
方法):
// 判断是否存在factoryMethodName
if (mbd.getFactoryMethodName() != null) {
// 存在的话,则通过factoryMethodName来进行初始化
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
通过factoryMethodName
初始化Bean
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
具体的初始化过程如下:
public BeanWrapper instantiateUsingFactoryMethod(
final String beanName, final RootBeanDefinition mbd, @Nullable final Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Object factoryBean;
Class<?> factoryClass;
boolean isStatic;
// 获取类构建方法所在配置类名称
String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
// 存在配置类名称,则@Bean是被标记在实例方法上
// 配置类与构建方法构建的目标类一致,抛出异常
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
factoryBean = this.beanFactory.getBean(factoryBeanName);
// 存在该构建目标的bean名称与容器内的其他Bean定义冲突,抛出异常
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;
}
else {
// @Bean标注在静态方法上
// 不存在构建目标的Class类型,则抛出异常。即:声明的类定义既不是一个Bean类,也不是一个类构建方法
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
Method factoryMethodToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
// 判断是否显示传入参数
// 如果不是显示传入参数,则根据constructorArgumentsResolved判断是否需要解析类构建方法的参数
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
Object[] argsToResolve = null;
// 使用锁,保证读取到的resolvedConstructorOrFactoryMethod、constructorArgumentsResolved、resolvedConstructorArguments以及preparedConstructorArguments是正确的,防止线程在其他线程修改的情况下读取错误的数据
// 查看是否存在一个类构建方法的缓存,不存在的话通过反射重新查找匹配,并在查找完成后,做storeCache的缓存作业
synchronized (mbd.constructorArgumentLock) {
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
// 找到一个缓存的构造方法(类构建方法或者类构造器)
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 对于传入的参数做解析
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
}
}
if (factoryMethodToUse == null || argsToUse == null) {
// 无构造方法,则通过反射查找匹配的方法
factoryClass = ClassUtils.getUserClass(factoryClass);
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
List<Method> candidateSet = new ArrayList<>();
for (Method candidate : rawCandidates) {
// 将匹配的方法放到列表内缓存(是否静态并且方法名是否一致)
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
candidateSet.add(candidate);
}
}
Method[] candidates = candidateSet.toArray(new Method[0]);
// 排序(按照是否公开方法,并且参数个数排序)
AutowireUtils.sortFactoryMethods(candidates);
ConstructorArgumentValues resolvedValues = null;
boolean autowiring = (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Method> ambiguousFactoryMethods = null;
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
// 因为没有通过程序性传入构造参数,所以需要手动判断并解析这些参数
// 如果存在构造参数,则解析这些参数
if (mbd.hasConstructorArgumentValues()) {
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
else {
minNrOfArgs = 0;
}
}
LinkedList<UnsatisfiedDependencyException> causes = null;
// 遍历与构造方法名字相同的所有方法
for (Method candidate : candidates) {
// 获取方法的参数类型列表
Class<?>[] paramTypes = candidate.getParameterTypes();
if (paramTypes.length >= minNrOfArgs) {
ArgumentsHolder argsHolder;
if (explicitArgs != null){
// 如果是显式声明的构造参数,则反射获得的构造方法参数类型长度与显示参数的个数需要保持一致
// 即这些参数都是必要性参数
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
else {
// 解析构造参数,这些参数可以是必填或者非必填
try {
String[] paramNames = null;
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
// 根据信息创建构造参数列表
argsHolder = createArgumentArray(
beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next overloaded factory method.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
// 根据定义的是否为宽松模式来做类型差异权重的判断
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// 选择最接近的一个构造方法
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
// 查出混淆的方法:防止出现相同名字、相同参数个数以及参数类型的方法;
// 收集这些方法并在出现多个的情况下抛出混淆异常。
// 这个检查只会在严格模式下执行并且会忽略掉重写的方法(Override)
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
!mbd.isLenientConstructorResolution() &&
paramTypes.length == factoryMethodToUse.getParameterCount() &&
!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
if (ambiguousFactoryMethods == null) {
ambiguousFactoryMethods = new LinkedHashSet<>();
ambiguousFactoryMethods.add(factoryMethodToUse);
}
ambiguousFactoryMethods.add(candidate);
}
}
}
// 未匹配到类构建方法的处理逻辑
if (factoryMethodToUse == null) {
// 判断是否存在异常,存在的话,执行Bean的回调onSuppressedException方法后,抛出异常
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
// 获取参数类型
List<String> argTypes = new ArrayList<>(minNrOfArgs);
if (explicitArgs != null) {
for (Object arg : explicitArgs) {
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
}
}
else if (resolvedValues != null){
Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
valueHolders.addAll(resolvedValues.getGenericArgumentValues());
for (ValueHolder value : valueHolders) {
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
argTypes.add(argType);
}
}
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
// 抛出未匹配到类构建方法的异常
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"No matching factory method found: " +
(mbd.getFactoryBeanName() != null ?
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
"Check that a method with the specified name " +
(minNrOfArgs > 0 ? "and arguments " : "") +
"exists and that it is " +
(isStatic ? "static" : "non-static") + ".");
}
// 对于返回类型为void的类构建方法,抛出异常
else if (void.class == factoryMethodToUse.getReturnType()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid factory method '" + mbd.getFactoryMethodName() +
"': needs to have a non-void return type!");
}
// 存在多个混淆方法,则抛出异常
else if (ambiguousFactoryMethods != null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous factory method matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousFactoryMethods);
}
// 将相关的构建信息存入缓存,用于以后的重新创建
if (explicitArgs == null && argsHolderToUse != null) {
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
}
try {
Object beanInstance;
// 创建类实例
if (System.getSecurityManager() != null) {
final Object fb = factoryBean;
final Method factoryMethod = factoryMethodToUse;
final Object[] args = argsToUse;
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
beanFactory.getInstantiationStrategy().instantiate(mbd, beanName, beanFactory, fb, factoryMethod, args),
beanFactory.getAccessControlContext());
}
else {
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse);
}
bw.setBeanInstance(beanInstance);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via factory method failed", ex);
}
}
实例创建详情如下:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, final Method factoryMethod, @Nullable Object... args) {
try {
// 设置类构建方法可访问
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(factoryMethod);
return null;
});
}
else {
ReflectionUtils.makeAccessible(factoryMethod);
}
// currentlyInvokedFactoryMethod用于判断当前线程是否正在创建某个bean
// 被用于BeanMethodInterceptor类的intercept方法
// 以及BeanMethodInterceptor类的resolveBeanReference方法
// 具体应用场景以及相关的使用情况待探究
// 备份之前的类构建方法
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
try {
// 设置构建方法为当前的类构建方法
currentlyInvokedFactoryMethod.set(factoryMethod);
// 执行构建方法并获得返回值,如果返回值为null,则返回NullBean实例
Object result = factoryMethod.invoke(factoryBean, args);
if (result == null) {
result = new NullBean();
}
return result;
}
finally {
// 恢复现场
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(factoryMethod,
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(factoryMethod,
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
}
catch (InvocationTargetException ex) {
String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
"declaring the factory method as static for independence from its containing instance. " + msg;
}
throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
}
}
@Bean的顺序
@Bean
如果在配置类内部,则可以根据如下这段代码知道:
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
// 尝试通过ASM从类文件判断方法的顺序...因为,JVM的标准反射库获取的方法顺序是随机的,甚至泡在相同JVM的不同应用返回的顺序也会不一致
try {
AnnotationMetadata asm =
this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
if (asmMethods.size() >= beanMethods.size()) {
Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
// 做了一遍过滤,将二进制class文件的方法与JVM反射的方法做一次对比,防止将非编程方法加入,保持与JVM反射获取方法一致,除了顺序。
for (MethodMetadata asmMethod : asmMethods) {
for (MethodMetadata beanMethod : beanMethods) {
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
selectedMethods.add(beanMethod);
break;
}
}
}
if (selectedMethods.size() == beanMethods.size()) {
// All reflection-detected methods found in ASM method set -> proceed
beanMethods = selectedMethods;
}
}
}
catch (IOException ex) {
logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
// No worries, let's continue with the reflection metadata we started with...
}
}
是根据代码编写顺序来执行。
如果实在不同的Configuration
类内,则判断依据移植到类层次。如果类实现了Ordered
接口或者注解有@Order
或者@Prority
,则根据他们的值获取排序,否则根据扫描的顺序来判定。
@Bean的覆盖问题
如果存在@Bean
注解内的name相同或者无name方法名相同,则根据@Bean
的顺序来进行对应的覆盖。
Spring会拦截所有标记为@Bean的方法,直接返回容器内单例对象
先说结论,这个观点是错误的。可以从@Bean的处理了解到,类的初始化,并没有判断是否调用了其他@Bean
注解的方法,是通过:
Object result = factoryMethod.invoke(factoryBean, args);
直接创建,那么可以肯定的是:调用其他@Bean
注解的方法,内部使用的对象与@Bean
本身创建的对象并不是同一个对象。同时,如果多个方法调用某个被注解有@Bean
的方法,则获取的内部对象也是不一样的。
方法级别的@Bean是否由AOP实现
同样的,创建过程一目了然,不是由AOP实现;不过,如果显示注解了@Scope
,并且非NONE,则会创建一个代理对象覆盖类定义。这个创建过程的确使用了类AOP的概念。