Spring源码探究(一) Spring-Bean解析

----------------------------------------------------------------------------------------------------------------

--由于最近的学习需要,决定对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是很不错的。

 

 

----------------------------未完待续----------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值