1. 提出问题
假设有如下实体类:
public class SupplierBean {
public Object getObject() {
return "hello";
}
}
在spring.xml文件中配置该Bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="supplierBean" class="com.xxx.SupplierBean"/>
</beans>
创建一个BeanFactory并获取该Bean,并打印其getObject()方法的结果:
public class Demo {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
SupplierBean supplierBean = ctx.getBean("supplierBean", SupplierBean.class);
// 显然,这里打印"hello"
System.out.println(supplierBean.getObject());
}
}
假设我们想要修改SupplierBean类的getObject()方法的返回值
最容易想到的做法是写一个SupplierBean的子类,并重写getObject()方法;但这种方式不是我们要讨论的
实际上,Spring提供了方法重写(即MethodOverride)机制,允许我们通过配置的方式来重写Bean的方法
Spring提供了LookupMethod和ReplacedMethod两种重写方式
需要注意的是,对于那些通过
@Bean注解注册的Bean,方法重写机制是不会生效的
这是因为方法重写的信息需要存到BeanDefinition中,而Spring在将@Bean方法转成BeanDefinition时,忽略了方法重写机制
2. LookupMethod
这种方式只能修改方法的返回值,且只能返回Spring容器管理的Bean(可以是多例的,这种情况下,方法的返回值会不断变化)
因此,被LookupMethod方式重写的方法就等价于BeanFactory的getBean()方法
如果希望方法的返回值固定从容器中获取,则可以使用这种方式
2.1. 配置文件方式
修改配置文件,如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置一个新的Bean,作为supplierBean的getObject()方法的返回值 -->
<bean id="lookupBean" class="java.lang.String" factory-method="valueOf">
<constructor-arg type="java.lang.Object" value="world" />
</bean>
<!-- 添加lookup-method标签,表示将该Bean的getObject()方法的返回值修改成lookupBean -->
<bean id="supplierBean" class="com.xxx.SupplierBean" >
<lookup-method name="getObject" bean="lookupBean" />
</bean>
</beans>
在测试程序中打印获取到的Bean:
public class Demo {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
SupplierBean supplierBean = ctx.getBean("supplierBean", SupplierBean.class);
// 这里的supplierBean是个代理对象:com.xxx.SupplierBean$$EnhancerBySpringCGLIB$$ba7bf0f2@6ac13091
System.out.println(supplierBean);
// 打印"world"
System.out.println(supplierBean.getObject());
}
}
2.2. 注解方式
@Component
public class SupplierBean {
/**
* 注册一个lookupBean
*/
@Bean
public Object lookupBean() {
return "world";
}
/**
* 使用@Lookup注解,将当前方法的返回值改为lookupBean
*/
@Lookup("lookupBean")
public Object getObject() {
return "hello";
}
}
public class Demo {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SupplierBean.class);
SupplierBean supplierBean = ctx.getBean("supplierBean", SupplierBean.class);
System.out.println(supplierBean);
System.out.println(supplierBean.getObject());
}
}
3. ReplacedMethod
这种方式的功能比
LookupMethod方式更强大,且优先级更高;可以看作是JDK动态代理和Spring的结合
一方面,这种方式的增强逻辑和JDK动态代理类似
另一方面,这种方式的方法处理器会被配置成Bean,因此可以通过实现Aware接口等方式来获取更多信息
3.1. MethodReplacer
ReplacedMethod方式需要先自定义一个MethodReplacer组件,用于封装重写方法的实现逻辑:
public class MyMethodReplacer implements MethodReplacer {
/**
* 重写目标方法;本方法和JDK动态代理的InvocationHandler.invoke()方法类似
*
* @param obj 代理对象
* @param method 被重写的方法
* @param args 方法的参数
*/
@Override
public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
// 打印代理对象,并返回自定义的数据
System.out.println(obj);
return "world";
}
}
3.2. 配置文件方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 将自定义的MethodReplacer注册为一个Bean -->
<bean id="myMethodReplacer" class="com.xxx.MyMethodReplacer" />
<!-- 添加replaced-method标签,表示重写该Bean的getObject()方法;重写逻辑放在myMethodReplacer中 -->
<bean id="supplierBean" class="com.xxx.SupplierBean" >
<replaced-method name="getObject" replacer="myMethodReplacer">
<!-- 此外,replaced-method标签内还可以配置arg-type标签 -->
<!-- 当有多个重载方法时,可以通过该标签来指定方法的参数类型,从而确定要重写哪个方法 -->
<!-- <arg-type match="com.xxx.XxxClass" /> -->
<!-- <arg-type>java.lang.String</arg-type> -->
</replaced-method>
</bean>
</beans>
测试程序及打印结果如下:
public class Demo {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
SupplierBean supplierBean = ctx.getBean("supplierBean", SupplierBean.class);
System.out.println(supplierBean);
System.out.println(supplierBean.getObject());
}
}
com.xxx.SupplierBean$$EnhancerBySpringCGLIB$$ba7bf0f2@16e7dcfd
com.xxx.SupplierBean$$EnhancerBySpringCGLIB$$ba7bf0f2@16e7dcfd
world
4. 源码解析:基本组件
4.1. InstantiationStrategy
AbstractAutowireCapableBeanFactory实现了createBean()方法,该方法负责创建Bean
创建Bean的过程主要包括:实例化Bean、依赖注入、调用init方法
其中,实例化Bean这一步是通过InstantiationStrategy组件来实现的
InstantiationStrategy组件在实例化Bean时,会判断该Bean是否有方法重写,如果有,则会创建该Bean的代理对象
注意,在实例化Bean时,可以通过无参构造器或有参构造器来创建;这里我们以无参构造器为例来讲解
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
/**
* Bean的实例化策略
*/
private InstantiationStrategy instantiationStrategy;
/**
* 通过无参构造器实例化Bean
*/
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
// 调用instantiationStrategy的instantiate()方法实例化Bean
// 这一步中,会判断该Bean是否有MethodOverride,如果有,则创建该Bean的代理对象
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this); // @Privileged
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
} catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
}
4.2. SimpleInstantiationStrategy
本类实现了InstantiationStrategy接口,主要负责直接实例化Bean:
public class SimpleInstantiationStrategy implements InstantiationStrategy {
/**
* 根据无参构造器来创建Bean实例
*/
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// 如果该Bean没有MethodOverride,则直接通过无参构造器实例化该Bean
if (!bd.hasMethodOverrides()) {
// 下面这块代码是在获取该Bean的无参构造器
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 {
constructorToUse = clazz.getDeclaredConstructor(); // @Privileged
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
} catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 根据构造器实例化Bean
return BeanUtils.instantiateClass(constructorToUse);
// 如果有MethodOverride,则需要创建Bean的代理对象
} else {
// instantiateWithMethodInjection()方法默认抛出UnsupportedOperationException异常,需要子类重写
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
}
4.3. CglibSubclassingInstantiationStrategy
本类继承自SimpleInstantiationStrategy,重写了instantiateWithMethodInjection()方法:
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
/**
* 根据无参构造器创建Bean的代理对象
*/
@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner){
return instantiateWithMethodInjection(bd, beanName, owner, null);
}
/**
* 根据指定构造器创建Bean的代理对象;如果不指定构造器,则采用无参构造器
*/
@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Constructor<?> ctor, Object... args) {
// 通过内部组件CglibSubclassCreator来创建Cglib代理对象;这个组件稍后再解析
return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}
/**
* 本类主要作为其它内部组件(如方法过滤器和方法拦截器)的父类
* 本类重写了equals()和hashcode()方法,确保同一个Bean的同一种类型的内部组件是等价的
*/
private static class CglibIdentitySupport {
private final RootBeanDefinition beanDefinition;
public CglibIdentitySupport(RootBeanDefinition beanDefinition) {
this.beanDefinition = beanDefinition;
}
public RootBeanDefinition getBeanDefinition() {
return this.beanDefinition;
}
@Override
public boolean equals(@Nullable Object other) {
return (other != null && getClass() == other.getClass() &&
this.beanDefinition.equals(((CglibIdentitySupport) other).beanDefinition));
}
@Override
public int hashCode() {
return this.beanDefinition.hashCode();
}
}
}
4.4. MethodOverrideCallbackFilter
先来看MethodOverrideCallbackFilter组件;该组件主要负责判断哪些方法需要增强
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
/**
* 常量0代表方法不需要进行增强
*/
private static final int PASSTHROUGH = 0;
/**
* 常量1代表方法需要进行LookupMethod增强
*/
private static final int LOOKUP_OVERRIDE = 1;
/**
* 常量2代表方法需要进行ReplacedMethod增强
*/
private static final int METHOD_REPLACER = 2;
/**
* 方法过滤器,用于判断Bean的指定方法是否需要重写、采用什么方式的重写机制
*/
private static class MethodOverrideCallbackFilter extends CglibIdentitySupport implements CallbackFilter {
/**
* 构造方法,需指定目标BeanDefinition
*/
public MethodOverrideCallbackFilter(RootBeanDefinition beanDefinition) {
super(beanDefinition);
}
/**
* 判断目标Bean的指定方法是否需要增强
*/
@Override
public int accept(Method method) {
// 获取该方法对应的MethodOverride(相当于xml文件中的lookup-method/replaced-method标签)
MethodOverride methodOverride = getBeanDefinition().getMethodOverrides().getOverride(method);
// 如果该方法没有对应的MethodOverride,则直接放行
if (methodOverride == null) {
return PASSTHROUGH;
// 否则,根据MethodOverride的类型返回相应的数值
} else if (methodOverride instanceof LookupOverride) {
return LOOKUP_OVERRIDE;
} else if (methodOverride instanceof ReplaceOverride) {
return METHOD_REPLACER;
}
throw new UnsupportedOperationException("Unexpected MethodOverride subclass: " +
methodOverride.getClass().getName());
}
}
}
4.5. CglibSubclassCreator
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
/**
* 本类负责为有方法重写机制的Bean创建代理对象
*/
private static class CglibSubclassCreator {
/**
* 回调(拦截器/增强逻辑)的类型
* 注意,拦截器的下标和MethodOverrideCallbackFilter的accept()方法的返回值是对应的
* 比如,方法过滤器的accept()方法返回1(LOOKUP_OVERRIDE),就代表要执行LookupOverrideMethodInterceptor的增强
*/
private static final Class<?>[] CALLBACK_TYPES = new Class<?>[]
{NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};
/**
* 要给哪个Bean创建代理对象
*/
private final RootBeanDefinition beanDefinition;
/**
* 所属BeanFactory
*/
private final BeanFactory owner;
/**
* 全参构造器
*/
CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) {
this.beanDefinition = beanDefinition;
this.owner = owner;
}
/**
* 创建Bean类的子类(代理对象的类型)
*/
private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(beanDefinition.getBeanClass());
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
if (this.owner instanceof ConfigurableBeanFactory) {
ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader();
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
}
// 设置方法过滤器
enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
// 设置拦截器类型;注意,这里设置的是拦截器类型,而不是具体的拦截器实例
// 拦截器实例会在子类对象实例化完成后才创建(这么做是为了避免内存泄漏)
enhancer.setCallbackTypes(CALLBACK_TYPES);
// 创建子类
return enhancer.createClass();
}
/**
* 根据指定构造方法创建Bean的代理对象
*/
public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
// 创建Bean类的子类
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
// 实例化子类对象
Object instance;
if (ctor == null) {
instance = BeanUtils.instantiateClass(subclass);
} else {
try {
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
instance = enhancedSubclassConstructor.newInstance(args);
} catch (Exception ex) {
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
}
}
// 给子类对象设置回调,将增强逻辑应用到子类对象之中;这里设置的callbacks要和CALLBACK_TYPES相对应
Factory factory = (Factory) instance;
factory.setCallbacks(new Callback[]{NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
return instance;
}
}
}
4.6. XxxOverrideMethodInterceptor
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
/**
* 与LookupOverride相关的方法拦截器
*/
private static class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
private final BeanFactory owner;
public LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
super(beanDefinition);
this.owner = owner;
}
/**
* 对指定方法进行LookupMethod增强
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
// 获取到该方法的LookupOverride配置
// 这里可以直接将MethodOverride强转为LookupOverride,并且它一定不为null
// 这是因为在方法过滤器中,我们已经对MethodOverride的类型进行过判断了
LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
Assert.state(lo != null, "LookupOverride not found");
// 将该方法的传参作为获取Bean时使用的参数
Object[] argsToUse = (args.length > 0 ? args : null);
// 如果指定了Lookup的Bean名称,则根据Bean名称和相应的参数来获取Bean,并将该Bean作为方法的返回值返回
if (StringUtils.hasText(lo.getBeanName())) {
Object bean = (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
this.owner.getBean(lo.getBeanName()));
// Detect package-protected NullBean instance through equals(null) check
return (bean.equals(null) ? null : bean);
// 否则,根据方法的返回值类型(可能涉及到泛型)获取相应类型的Bean并返回
} else {
ResolvableType genericReturnType = ResolvableType.forMethodReturnType(method);
return (argsToUse != null ? this.owner.getBeanProvider(genericReturnType).getObject(argsToUse) :
this.owner.getBeanProvider(genericReturnType).getObject());
}
}
}
/**
* 与ReplaceOverride相关的方法拦截器
*/
private static class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
private final BeanFactory owner;
public ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
super(beanDefinition);
this.owner = owner;
}
/**
* 对指定方法进行ReplacedMethod增强
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
// 获取到该方法的ReplaceOverride配置
ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
Assert.state(ro != null, "ReplaceOverride not found");
// 获取到对应的MethodReplacer组件并调用其reimplement()方法
// TODO could cache if a singleton for minor performance optimization
MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
return mr.reimplement(obj, method, args);
}
}
}
5. 源码解析:重写机制
5.1. MethodOverride
/**
* 本类代表Bean的方法重写信息;一个Bean可以对应多个MethodOverride
* 注意,方法重写机制不能作为插入横切的通用方式(也就是说,方法重写机制不能代替AOP)
*/
public abstract class MethodOverride implements BeanMetadataElement {
/**
* 被重写的方法的名称
*/
private final String methodName;
/**
* 该方法是否有重载方法
* 如果为false,说明类中只有一个名称为methodName的方法
* 如果为true,说明类中有多个名称为methodName的方法,或者未解析类中的方法(即未知)
*/
private boolean overloaded = true;
/**
* 该MethodOverride的配置源
* 该字段的作用我不太清楚,而且该字段的用处较少,因此可以先忽略
*/
@Nullable
private Object source;
/**
* 构造器,需指定方法名称
*/
protected MethodOverride(String methodName) {
Assert.notNull(methodName, "Method name must not be null");
this.methodName = methodName;
}
// 这里省略了以上3个字段的set/get方法,以及equals()/hashcode()方法
/**
* 抽象方法;判断本MethodOverride配置是否要应用到目标方法中(即目标方法是否需要重写)
*/
public abstract boolean matches(Method method);
}
/**
* 本类代表Bean的LookupMethod增强信息
* 被重写的方法可以有形参;当从容器中获取目标Bean时,方法的参数将会被传到容器的getBean()方法中
*/
public class LookupOverride extends MethodOverride {
/**
* 要返回的Bean的名称
*/
@Nullable
private final String beanName;
/**
* 被重写的方法
*/
@Nullable
private Method method;
/**
* 构造器1:需指定被重写的方法的名称和目标Bean名称
* 如果是xml文件配置,则使用该构造器来创建LookupOverride对象
*/
public LookupOverride(String methodName, @Nullable String beanName) {
super(methodName);
this.beanName = beanName;
}
/**
* 构造器2:需指定被重写的方法和目标Bean名称
* 如果是通过@Lookup注解来配置的,则使用该构造器来创建LookupOverride对象
*/
public LookupOverride(Method method, @Nullable String beanName) {
super(method.getName());
this.method = method;
this.beanName = beanName;
}
/**
* 获取要返回的Bean的名称
*/
@Nullable
public String getBeanName() {
return this.beanName;
}
/**
* 判断目标方法是否需要进行Lookup增强
*/
@Override
public boolean matches(Method method) {
// 如果是通过@Lookup注解配置的,则直接判断this.method是否和目标方法相同
if (this.method != null) {
return method.equals(this.method);
// 否则,如果同时满足以下两个条件,则目标方法需要被重写:
// 1. 目标方法的名称和本类要重写的方法的名称相同
// 2. Bean类中只有一个该名称的方法,或者目标方法是抽象的,或者目标方法是无参的(即默认重写无参方法)
} else {
return (method.getName().equals(getMethodName()) && (!isOverloaded() ||
Modifier.isAbstract(method.getModifiers()) || method.getParameterCount() == 0));
}
}
// 这里省略了equals()/hashcode()/toString()方法
}
/**
* 本类代表Bean的ReplacedMethod增强信息
*/
public class ReplaceOverride extends MethodOverride {
/**
* 目标MethodReplacer组件的Bean名称
*/
private final String methodReplacerBeanName;
/**
* 目标方法的参数类型(即arg-type标签的内容)
*/
private final List<String> typeIdentifiers = new ArrayList<>();
/**
* 构造器,需指定目标方法名称和目标MethodReplacer组件的Bean名称
*/
public ReplaceOverride(String methodName, String methodReplacerBeanName) {
super(methodName);
Assert.notNull(methodReplacerBeanName, "Method replacer bean name must not be null");
this.methodReplacerBeanName = methodReplacerBeanName;
}
/**
* 获取MethodReplacer组件的Bean名称
*/
public String getMethodReplacerBeanName() {
return this.methodReplacerBeanName;
}
/**
* 添加方法参数类型;每解析完一个arg-type标签,就会调用一次本方法
* 这里的identifier可以是全限定类名的子串,比如"Object"或"java.lang.Obj"等
*/
public void addTypeIdentifier(String identifier) {
this.typeIdentifiers.add(identifier);
}
/**
* 判断目标方法是否需要进行Replace增强
*/
@Override
public boolean matches(Method method) {
// 如果方法名称不一致,则不重写
if (!method.getName().equals(getMethodName())) {
return false;
}
// 如果Bean类只有一个该名称的方法,则重写该方法
if (!isOverloaded()) {
return true;
}
// 否则,说明有多个重载方法或者未对Bean类中的方法进行解析
// 这种情况下,要求目标方法的参数类型和本类中的typeIdentifiers必须完全匹配
if (this.typeIdentifiers.size() != method.getParameterCount()) {
return false;
}
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < this.typeIdentifiers.size(); i++) {
String identifier = this.typeIdentifiers.get(i);
// 注意这里调用的是String的contains()方法而不是equals()方法
if (!parameterTypes[i].getName().contains(identifier)) {
return false;
}
}
return true;
}
// 这里省略了equals()/hashcode()/toString()方法
}
5.2. MethodOverrides
/**
* 代表MethodOverride集合
* 一个Bean可以配置多个MethodOverride,因此使用本组件来管理单个Bean的所有MethodOverride配置
* 用于判断某个Bean是否有要重写的方法,以及Bean的某个方法是否需要重写
*/
public class MethodOverrides {
/**
* 该Bean的所有MethodOverride配置;注意,这里是用CopyOnWriteArraySet集合来保存的
*/
private final Set<MethodOverride> overrides = new CopyOnWriteArraySet<>();
public MethodOverrides() {
}
public MethodOverrides(MethodOverrides other) {
addOverrides(other);
}
public void addOverrides(@Nullable MethodOverrides other) {
if (other != null) {
this.overrides.addAll(other.overrides);
}
}
public void addOverride(MethodOverride override) {
this.overrides.add(override);
}
public Set<MethodOverride> getOverrides() {
return this.overrides;
}
public boolean isEmpty() {
return this.overrides.isEmpty();
}
/**
* 判断目标方法是否需要重写;如果需要重写,则返回相应的MethodOverride
*/
@Nullable
public MethodOverride getOverride(Method method) {
MethodOverride match = null;
// 遍历overrides集合,获取到最后一个能和目标方法匹配的MethodOverride
// 注意,由于overrides是CopyOnWriteArraySet类型,并且lookup-method标签先于replaced-method标签解析
// 因此,如果LookupOverride和ReplaceOverride能同时匹配目标方法,则最终生效的是ReplaceOverride
for (MethodOverride candidate : this.overrides) {
if (candidate.matches(method)) {
match = candidate;
}
}
return match;
}
// 这里省略了equals()/hashcode()方法
}
5.3. prepareMethodOverride()
/**
* 抽象的BeanDefinition
*/
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
/**
* 该Bean的方法重写信息
*/
private MethodOverrides methodOverrides = new MethodOverrides();
/**
* 验证并解析当前Bean的所有MethodOverride;在创建Bean前会先调用该方法
*/
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
if (hasMethodOverrides()) {
getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
}
}
/**
* 验证并解析当前Bean的指定MethodOverride
*/
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
// 获取Bean类中所有名称为methodName的方法(包括父类/接口中的方法和非公开的方法)
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
// 没找到该名称的方法,则直接报错
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
// 如果只有一个该名称的方法,则将MethodOverride的overloaded置为false,从而提高MethodOverride.match()方法的效率
} else if (count == 1) {
mo.setOverloaded(false);
}
}
}