今天在看spring bean的源码,看到bean的创建时,发现代码中使用了cglib动态代理。立即想起以前研发答辩的时候,有个考官非常喜欢问,spring注入抽象类原理是什么。
出于兴趣,决定进行一次测试。
首先定义程序员接口如下:
public interface Programmer {
void programming();
}
接着实现java程序员类如下:
public class JavaProgrammer implements Programmer {
@Override
public void programming() {
System.out.println("I'm writing java code!");
}
}
编写程序员测试抽象类如下:
public abstract class ProgrammerTest {
public void programming(){
getProgrammer().programming();
}
public abstract Programmer getProgrammer();
}
spring bean的配置如下:
<bean id ="javaProgrammer" class="com.zzl.JavaProgrammer">
</bean>
<bean id ="programmerTest" class="com.zzl.ProgrammerTest">
<lookup-method name="getProgrammer" bean="javaProgrammer"/>
</bean>
编写cglib测试类如下:
public class CglibTest {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
ProgrammerTest programmerTest=(ProgrammerTest) ac.getBean("programmerTest");
programmerTest.programming();
}
}
运行CglibTest类结果如下:

通过结果,我们可以看到,spring成功实例化了抽象类ProgrammerTest。
spring实现此功能的关键代码是SimpleInstantiationStrategy类的instantiate方法,代码如下:
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (bd.getMethodOverrides().isEmpty()) {
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(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
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);
}
}
我们可以看到methodOverrides不为空的时候,会使用cglib实例化bean对象。而methodOverrides是在BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法中通过如下两行代码赋值的,前面举例的spring配置文件中的lookup-method元素满足了此条件。
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
至此,我们通过举例成功完成了spring对抽象类的注入,并对spring的实现过程进行了分析。
文章转载自磊哥谈技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




