springboot 实现bean手动注入操作

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)方法,通过反射将值设置到属性中

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • 在springboot中实现个别bean懒加载的操作

    懒加载---就是我们在spring容器启动的是先不把所有的bean都加载到spring的容器中去,而是在当需要用的时候,才把这个对象实例化到容器中. @Lazy 在需要懒加载的bean上加上@Lazy就可以了 补充知识:springboot组件懒加载的坑及加载规则 什么是懒加载? 懒加载的意思是不在项目启动的时候实例出来这个组件 @RestController public class ApiController { @Autowired Skill kobSkillImpl; @Request

  • Springboot实现多线程注入bean的工具类操作

    场景: 使用springboot多线程,线程类无法自动注入需要的bean 解决方法: 通过工具类获取需要的bean 工具类代码: import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springfram

  • springboot bean扫描路径的实现

    1:默认扫描启动类所在路径下所有的bean 2:可以在启动类中添加注解,手动指定扫描路径: @ComponentScan(basePackages = {"com.xxx.service1.*","com.xxx.service2.**"}) 补充:SpringBoot 是如何通过 @SpringBootApplication 扫描项目中的 Bean 原因 首先因为 XXXXXXXApplication 附带 @SpringBootApplication 注解,而

  • SpringBoot普通类获取spring容器中bean的操作

    前言 在spring框架中,是无法在普通类中通过注解注入实例的,因为sping框架在启动的时候,就会将标明交给spring容器管理的类进行实例化,并梳理他们彼此的依赖关系,进行注入,没有交给spring容器管理的普通类,是不会进行注入的,即使你使用了注入的相关注解.这个时候,如果我们需要在普通类中获取spring容器中的实例,就需要一些特定的方法,这里将整理一下如何在springboot中实现这样的方法. 创建springboot工程demo 项目结构图示 项目结构说明 service包下为de

  • springboot2.x解决运行顺序及Bean对象注入顺序的问题

    1 前言 通过指定接口,重写指定方法,可以在Bean对应的生命周期方法中执行相应的程序 2 测试 本文将分析几个Bean对象,为它们设置优先级(通过@Order),然后再打断点调试,测试各种生命周期方法的运行的顺序 在项目当中最让人头疼的就是bean对象不被注入的问题,通过本文,你可以很好的解决这个问题. 先看看本程序使用的依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="

  • 解决springboot bean中大写的字段返回变成小写的问题

    例如我的bean中有以下4个字段 private String code; private String _TOKENUUMS; private String TGC; private String U; 在返回的json里只会显示 {"code":"xx","tgc":"xx","u":"xx"} 大小会变成小写,特殊符号开头的字段都不会显示,其原因是因为springboot在进行序列

  • springboot 实现bean手动注入操作

    1.springboot启动类实现接口ApplicationListener<ContextRefreshedEvent>,实现方法onApplicationEvent,初始化上下文 package test.projectTest; import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration; import org.springframework.boot.SpringApplication; import or

  • java SpringBoot自定义注解,及自定义解析器实现对象自动注入操作

    # java-SpringBoot自定义参数解析器实现对象自动注入 解析器逻辑流程图表 后台解析注解的解析器 首先,我在java后台编写了一个解析器,代码如下 import com.ruoyi.framework.interceptor.annotation.LoginUser; import com.ruoyi.project.WebMoudle.WebUser.domain.WebUser; import com.ruoyi.project.WebMoudle.WebUser.service

  • springboot 启动如何排除某些bean的注入

    springboot 启动排除某些bean的注入 问题: 最近做项目的时候,需要引入其他的jar.然后还需要扫描这些jar里的某些bean.于是使用注解:@ComponentScan 这个注解直接指定包名就可以,它会去扫描这个包下所有的class,然后判断是否解析: @ComponentScan(basePackages = {"your.pkg","other.pkg"}) public class Application { } 其他的jar中定义了 redis

  • Spring运行时手动注入bean的方法实例

    有时候,会有这样一个需求,在程序运行时动态生成的对象,需要注入到Spring容器中进行管理. 下面是获取Bean以及注入Bean的工具类 import org.springframework.beans.BeansException; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinit

  • 关于SpringBoot拦截器中Bean无法注入的问题

    问题 这两天遇到SpringBoot拦截器中Bean无法注入问题.下面介绍我的思考过程和解决过程: 1.由于其他bean在service,controller层注入一点问题也没有,开始根本没意识到Bean无法注入是在拦截器中无效的问题,一直在查找注解指定的包在哪里配置的,然而却找不到配置,Springboot是用java类的形式加载配置的.在网络的某个角落看到这样的说法: SpringBoot项目的Bean装配默认规则是根据Application类所在的包位置从上往下扫描! "Applicati

  • Springboot 在普通类型注入Service或mapper

    目录 Springboot 在普通类型注入Service或mapper 1.由于之前都是通过controller调用service层来实现访问 2.在拿到数据之后,掉service时出现空指针 springboot 普通类怎么使用注入 Springboot 在普通类型注入Service或mapper 最近遇到一个难题(大佬可能感觉这太简单了把),对于我这样的小白来说,确实有些头疼. 接下来说一下我遇到的问题,在spring boot中创建了一个UDP客户端,用于监听UDP服务端发送到数据.在实现

  • springboot整合redis进行数据操作(推荐)

    redis是一种常见的nosql,日常开发中,我们使用它的频率比较高,因为它的多种数据接口,很多场景中我们都可以用到,并且redis对分布式这块做的非常好. springboot整合redis比较简单,并且使用redistemplate可以让我们更加方便的对数据进行操作. 1.添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starte

  • SpringBoot下的值注入(推荐)

    在我们实际开发项目中,经常会遇到一些常量的配置,比如url,暂时不会改变的字段参数,这个时候我们最好是不要直接写死在代码里的,因为这样编写的程序,应用扩展性太差了,我们可以直接写在配置文件中然后通过配置文件读取该字段的值,这样的话以后需要更改,也不用在重新修改代码,好处不言而知. 一,字段直接注入 @Value("${example.url}") private String url; 这样直接在配置文件里写url值即可(application.properties|applicati

  • Spring框架设值注入操作实战案例分析

    本文实例讲述了Spring框架设值注入操作.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <!-- Spring配置文件的根元素,使用spring-beans-4.0.xsd语义约束 --> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http:

随机推荐