----------------------------------------------------------------------------------------------------------------
--由于最近的学习需要,决定对Spring框架做一个深入的了解,之前的内容暂时搁置--
----------------------------------------------------------------------------------------------------------------
Spring最为瞩目的一大特征就是其作为Bean对象的管理容器,那么我们在这里就尝试着以Bean对象作为切入点,去探寻源码的秘密。作为和Bean最为密切的联系的注解@Autowired一定是我们最为熟悉的注解,搜索源码找到:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
通过阅读类注释,我们知道了关于这一整套的自动装配的信息:将注解打在构造器、属性、setter方法或者config方法上,让其能够通过Spring的依赖注入注入属性。有且只有一个构造器可以被注解Autowired修饰,用来指向当该类作为Spring bean对象被创建时的构造方法,这个方法不需要是共有的。属性将会在类被构造完毕后,任何config方法运行前注入。属性也不必是共有的。
config方法必须有一个随意的名称和任意多的入参,这些入参将会从Spring容器中取出符合的Bean对象注入。setter方法是一种特殊的config方法。这些方法也不需要是共有的。设置required属性将会对方法中所有的入参应用。特别的参数应该考虑使用java-8的Optional类或者使用注解@Nullable来覆盖required的语义。对于Collection和Map,将会按照声明的值类型注入bean。因此Map的key值必须是String类型,这决定了他关联的bean对象的名称。可以用Order来修饰注入的顺序,否则就按照它们既有的顺序注入。注意,实际的注入操作是通过BeanPostProcessor来完成了,这表明了你不能向BeanPostProcessor对象和BeanFactoryPostProcessor对象利用@Autowired注入对象。更多请参考AutowiredAnnotationBeanPostProcessor。
顺着BeanPostProcessor,我们找到:InstantiationAwareBeanPostProcessor 类、SmartInstantiationAwareBeanPostProcessor类、InstantiationAwareBeanPostProcessorAdapter类,为处理器添加了一些方法声明(源码都是一些接口,可以看一眼)。
仔细分析类AutowiredAnnotationBeanPostProcessor :
这个方法告诉我们@Autowired,@Value,@Inject注解都是可以用到注入的。
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
方法很长,如方法名,本身是用来定义候选的构造函数。方法分为上下两部分,上部主要处理@Lookup注解,下部主要是匹配候选的构造函数(Primary Constructor的概念可以再Kotlin里查阅)
@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
throws BeanCreationException {
......
}
----@Lookup:解释起来也很简单,Spring的BeanFactory默认是单例的,我们可以设置其为多例,但是在A对象中注入B对象作为其属性,即使B对象是多例的,在多次通过A对象getB()时取出来的对象也是一样的,如果我们希望在每次取出都能得到不同的对象,就需要@Lookup注解。
----sythetic:一个非常冷门的关键字,我们来看一个例子:
public class OuterClass{
private static InnerClass{
private String s = "hello world";
}
public static void main(String... args){
System.out.println(new OuterClass.InnerClass().s);
}
}
外部类new内部类对象,调用内部类静态属性值,从语义上说完全符合逻辑,但是在编译器看来,事情就没这么简单了。编译器通常会生成一个sythetic方法来获取静态属性的值(可以在代码中尝试Method.isSythetic()),同样的创建一个new内部类的构造函数,通过访问这个函数就可以得到内部类的对象了。
详细可以参考:http://www.cnblogs.com/bethunebtj/p/7761596.html
这个方法其实是给管理的Bean对象注入属性的:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
看findAutowiringMetadata,我们很容易知道,@Autowired只能注解在非static修饰的变量和有参数的非static的方法上(同上排除了sythetic的情况)(原因很好理解,你需要有对象,static一定不能行)。
看inject方法,注入方式简单粗暴:
ReflectionUtils.makeAccessible(field);
通过使方法/属性成为可访问的状态,直接传入对象/给属性赋值。
其余的方法多为辅助的工具方法,这里就不列举了。
OK,那么关于Autowired我们了解了七七八八,接下来就是研究整个BeanFactory的流程了,通过上面的源码中涉及到的ConfigurableListableBeanFactory接口,通过找到它的实现,我们从中可以发现线索:
内容比较多且杂,可能一时间无法厘清,我们首先通过分析,知道这是一个单例Bean的预加载(初始化之前的工作)。并且知道了对普通Bean对象和FactoryBean对象有不同的处理手段,以及一个关于Spring 4.1的新特性:
@Override
public void preInstantiateSingletons() throws BeansException {
......
// 获得所有 Bean 名字的集合
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 遍历 Bean 名字的集合,触发 Bean 加载
for (String beanName : beanNames) {
// 获得 RootBeanDefinition 对象
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 单例 && 非延迟加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 如果是 FactoryBean
if (isFactoryBean(beanName)) {
// 获得 FactoryBean 自身这个 Bean
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
// 判断是否要提前初始化
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
} else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
// 如果要,加载 FactoryBean 要创建的 Bean 对象
if (isEagerInit) {
getBean(beanName);
}
}
} else {
// 如果非 FactoryBean ,直接加载 Bean 对象
getBean(beanName);
}
}
}
// 遍历所有单例 Bean ,触发后置初始化方法,即 SmartInitializingSingleton 对象,所有非 lazy 单例 Bean 实例化完成后的回调方法。
// Spring 4.1 新增的特性
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) { // 安全模式
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
我们先来弄清楚FactoryBean到底是什么:
/**
* 一般情况下,Spring 通过反射机制利用 bean 的 class 属性指定实现类来实例化 bean 。
* 某些情况下,实例化 bean 过程比较复杂,如果按照传统的方式,则需要在 <bean> 中提供大量的配置信息,
* 配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring 为此提供了一个 FactoryBean 的工厂类接口,
* 用户可以通过实现该接口定制实例化 bean 的逻辑。
*
* FactoryBean 接口对于 Spring 框架来说占有重要的地位,Spring 自身就提供了 70 多个 FactoryBean 的实现
* 它们隐藏了实例化一些复杂 bean 的细节,给上层应用带来了便利。
*/
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
在这里我举一个简单的例子:
public class Dog {
private String name = "旺财";
private int age = 25;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class MyFactoryBean implements FactoryBean<Dog>{
@Override
public Dog getObject() throws Exception {
Dog dog = new Dog();
dog.setName("军儿");
return dog;
}
@Override
public Class<Dog> getObjectType() {
return Dog.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Configuration
public class Test{
@Bean
public MyFactoryBean mfb() {
return new MyFactoryBean();
}
public static void main(String[] args) throws Exception {
ApplicationContext ac = new AnnotationConfigApplicationContext(Test.class);
MyFactoryBean mfb = ac.getBean(MyFactoryBean.class);
Dog object = mfb.getObject();
System.out.println(object.getName());
}
}
这样我们就得到了我们想要的bean对象。如果你想要单例的对象,可以修改MyFactoryBean,使其持有一个Dog对象,并返回这个持有的对象。这种利用工厂的方式获取bean是很不错的。
----------------------------未完待续----------------------------