springboot 实现bean手动注入操作
作者:mengda_lei
1、springboot启动类实现接口ApplicationListener<ContextRefreshedEvent>,实现方法onApplicationEvent,初始化上下文
package test.projectTest; import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.system.ApplicationPidFileWriter; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import test.projectTest.util.SpringContextUtil; @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class, MybatisAutoConfiguration.class}) @SpringBootApplication(scanBasePackages={"test.projectTest"}) public class TestApplication implements ApplicationListener<ContextRefreshedEvent> { public static void main( String[] args ) { SpringApplication application = new SpringApplication(TestApplication.class); application.addListeners(new ApplicationPidFileWriter()); application.run(args); System.out.println( "启动成功" ); } @Override public void onApplicationEvent(ContextRefreshedEvent event) { SpringContextUtil.setApplicationContext(event.getApplicationContext()); } }
2.SpringContextUtil工具类初始化ApplicationContext applicationContext
package test.projectTest.util; import org.springframework.context.ApplicationContext; /** * 获取spring容器,以访问容器中定义的其他bean */ public class SpringContextUtil{ //spring上下文 private static ApplicationContext applicationContext; /** * 实现ApplicationContextAware接口的回调方法,设置上下文环境 * @param applicationContext */ public static void setApplicationContext(ApplicationContext applicationContext){ if(null==SpringContextUtil.applicationContext) SpringContextUtil.applicationContext=applicationContext; } public static ApplicationContext getApplicationContext(){ return applicationContext; } /** * 通过name获取 Bean. * * @param name * @return */ public static Object getBean(String name) { return getApplicationContext().getBean(name); } /** * 通过name获取 Bean. * * @param clazz * @return */ public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } /** * 通过name,以及Clazz返回指定的Bean * * @param name * @param clazz * @return */ public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } }
3.获取bean
package test.projectTest.util; import test.projectTest.mapper.slave.DailyDataMapper; public class TestUtil{ private static DailyDataMapper dailyDataMapper; static{//手动注入bean if(dailyDataMapper==null){ dailyDataMapper = (DailyDataMapper)SpringContextUtil.getBean("dailyDataMapper"); } } public static void test(){ dailyDataMapper.selectByPrimaryKey(1); } }
补充:springboot中bean的实例化和属性注入过程
springboot版本(2.0.4 RELEASE)
大致描述springboot中bean的实例化和属性注入过程流程
1) 在某一时刻Spring调用了Bean工厂的getBean(beanName)方法。beanName可能是simpleController,或者simpleService,simpleDao,顺序没关系(因为后面会有依赖关系的处理)。我们假设simpleController吧
2)getBean方法首先会调用Bean工厂中定义的getSingleton(beanName)方法,来判断是否存在该名字的bean单例,如果存在则返回,方法调用结束(spring默认是单例,这样可以提高效率)
3) 否则,Spring会检查是否存在父工厂,如果有则返回,方法调用结束
4) 否则,Spring会检查bean定义(BeanDefinition实例,用来描述Bean结果,component-scan扫描后,就是将beanDefinition实例放入Bean工厂,此时还没有被实例化)是否有依赖关系,如果有,执行1)步,获取依赖的bean实例
5) 否则,Spring会尝试创建这个bean实例,创建实例前,Spring会检查调用的构造器,并实例化该Bean,(通过Constructor.newInstance(args)进行实例化)
6) 实例化完成后,Spring会调用Bean工厂的populateBean方法来填充bean实例的属性,也就是自动装配。populateBean方法便是调用了BeanPostProcessor实例来完成属性元素的自动装配工作
7)在元素装配过程中,Spring会检查被装配的属性是否存在自动装配的其他属性,然后递归调用getBean方法,知道所有@Autowired的元素都被装配完成。如在装配simpleController中的simpleService属性时,发现SimpleServiceImpl实例中存在@Autowired属性simpleDao,然后调用getBean(simpleDao)方法,同样会执行1)----7)整个过程。所有可以看成一个递归过程。
8)装配完成后,Bean工厂会将所有的bean实例都添加到工厂中来。
Bean的实例化
1. 进入SpringApplication类中refreshContext()方法
2. 进入AbstractApplicationContext类中refresh()方法,找到this.finishBeanFactoryInitialization()方法,这个方法就是完成beanFactory的实例化
3. 进入AbstractApplicationContext类中finishBeanFactoryInitialization()方法,找到preInstantiateSingletons()
4. 进入DefaultListableBeanFactory类中preInstantiateSingletons()方法,找到getBean()方法
5. 进入AbstractBeanFactory类中getBean()方法,找到doGetBean()方法
6. 在AbstractBeanFactory类中doGetBean方法中,找到createBean()方法
7. 进入AbstractAutowireCapableBeanFactory类中createBean方法中,找到doCreateBean()方法
8. 在AbstractAutowireCapableBeanFactory类中doCreateBean()方法中,找到createBeanInstance()方法,看名字就知道是实例化bean的
9. 在AbstractAutowireCapableBeanFactory类createBeanInstance()方法中,找到instantiateBean()方法
10. 在AbstractAutowireCapableBeanFactory类instantiateBean()方法中,找到instantiate()方法
11. 在SimpleInstantiationStrategy类instantiate()方法中,找到instantiateClass()方法
12. 在BeanUtils类instantiateClass()方法中,可知bean的实例化是通过Constructor.newInstance()进行实例化
Bean的属性注入
1. 在AbstractAutowireCapableBeanFactory类doCreateBean()方法中,找到populateBean()方法,从名字可知是用来填充bean的
2. 在AbstractAutowireCapableBeanFactory类中populateBean()方法,找到postProcessPropertyValues()方法
3. 进入AutowiredAnnotationBeanPostProcessor类中postProcessPropertyValues()方法中,找到findAutowiringMetadata()方法,在这个方法中,如果属性中含有@Autowired注解则会递归getBean()。没有然后进入inject()方法中
4. 进入AutowiredAnnotationBeanPostProcessor类inject方法中,找到resolveDependency()方法,通过这个方法获取对应字段的值
5. 进入AutowiredAnnotationBeanPostProcessor类inject方法中,找到field.set(bean, value)方法,通过反射将值设置到属性中
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。