暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

spring通过cglib注入抽象类

磊哥谈技术 2018-11-08
1206

       今天在看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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论