前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >把对象交给spring管理的3种方法及经典应用

把对象交给spring管理的3种方法及经典应用

作者头像
静儿
发布2021-08-23 15:04:37
1.2K0
发布2021-08-23 15:04:37
举报
文章被收录于专栏:编程一生编程一生

背景

先说一说什么叫把对象交给spring管理。它区别于把类交给spring管理。在spring里采用注解方式@Service、@Component这些,实际上管理的是类,把这些类交给spring来负责实例化。

而对象交给spring管理,举个例子,最常见的在配置文件里定义一个bean,或者JavaConfig的方式就是在@Configure标签标注的类里的@Bean对象。这些Bean已经new出来了。是以对象实例的方式交给spring管理的。这些对象往往是与业务无关的基础组件。比如datasource的bean、redis连接池的bean。个数是有限的。

特别是面试的时候千万要注意他们的区别。有时候有的人觉得自己回答没问题,最后面试没通过,很可能是因为没有弄清楚面试的考察点。面试官的逻辑是如果你没弄清楚问题就回答,面试官很可能会怀疑工作中接到任务也会没有弄清楚就直接开干,做出些负产出来。建议面试的时候不但回答问题,同时也可以说对象交给spring管理和类交给spring管理有点类似,但是……这样清楚的表达自己的思考。

方法一:XML配置Bean

这个方法非常常见,举个例子:

代码语言:javascript
复制
<bean id="car" class="com.lm.spring.bean.Car">

这种定义方法相当于Car car = new Car() 然后 注册car到spring容器。用的时候直接用。

既然bean是被实例化后的对象,就涉及到对象实例化的时候要传参数的问题。

代码语言:javascript
复制
<bean id="car" class="com.lm.spring.bean.Car">
     <constructor-arg value="Baoma"></constructor-arg>
     <constructor-arg value="Red"></constructor-arg>
     <constructor-arg value="400000"></constructor-arg>
</bean>

这是构造器传参方式,相当于

Car car = new Car("Baoma","Red","400000")。当然构造器传参还支持指定参数的index或者name啥的。其中value代表是基本数据类型,也可以传对象,对象用ref=,代表传的是另外一个bean.

经典的配置场景是数据库配置:先配置dataSource,再配置需要引用dataSource的sessionFactory。

代码语言:javascript
复制
<!-- 数据源配置 -->
 <bean id="ds" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
      <!-- 基本属性 url、user、password -->
      <property name="url" value="#{props.url}" />
      <property name="username" value="#{props.user}" />
      <property name="password" value="#{props.password}" />
      <!-- 配置初始化大小、最小、最大 -->
      <property name="initialSize" value="#{props.initialPoolSize}" />
      <property name="minIdle" value="#{props.minPoolSize}" />
      <property name="maxActive" value="#{props.maxPoolSize}" />
      <!-- 配置获取连接等待超时的时间 -->
      <property name="maxWait" value="#{props.maxIdleTime}" />
      <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
      <property name="timeBetweenEvictionRunsMillis" value="#{props.timeBetweenEvictionRunsMillis}" />
      <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
      <property name="minEvictableIdleTimeMillis" value="#{props.minEvictableIdleTimeMillis}" />
      <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
      <property name="poolPreparedStatements" value="true" />
      <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
  </bean>

 <!-- sessionFactory  -->
 <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
      <property name="dataSource" ref="ds"></property>
      <!-- <property name="hibernateProperties"></property> -->
      <property name="configLocation" value="classpath:com/chinasofti/etc/conf/hibernate.cfg.xml"></property>
 </bean>

这些都是常规用法。前段时间见到了另外一种用法,虽然没啥技术难度。确实之前没有这么用过,也觉得很有意思:

代码语言:javascript
复制
<bean id="car" class="java.util.ArrayList">
    <property name="cars">
      <list>
        <ref bean="car1"></ref>
        <ref bean="car2"></ref>
        <ref bean="car3"></ref>
      </list>
    </property>  
  </bean>

这里用property方法传参相当于调用set方法传参。当然,这里除了可以定义ArrayList对象,还可以定义HashMap、HashSet、Array。

我看到这个恍然大悟,原来自己写的一些方法都不地道。比如机房信息,一个公司可能有七八个机房,什么大兴机房、永丰机房啥的。这个内容很少,放在数据库里没啥必要,之前项目就直接在程序里用枚举定义出来,然后放到map里的。如果加了个机房,就改改代码上线呗。

其实更合适的方法,应该是在配置文件里定义一个class="java.util.map"的bean。然后把内容都放到配置文件里。这些每次添加机房,只改配置文件,不改代码,更合理一些。

虽然实际来讲哈,现在都走devops工具发布了,成本工作量是一样的。但是这样写,能明确修改的是配置,不是代码逻辑。影响范围会更明确些。

方法二:@Bean

这个方法是spring boot流行后的常用方法。本质和XML配置方法相同。所有用XML配置文件的方法都可以用这个方法改写。

代码语言:javascript
复制
@Configuration //此处为配置项
public class ServiceConfig {
    @Bean //此处返回的是一个Spring的配置Bean,与xml的<bean>等价
    public IMessageService getMessageService() {//方法名称随便写
        return new MessgeServiceImpl();
    }
}

很多基础组件的使用文档提供的是XML配置形式的,看到过一些刚毕业的同学在抓耳挠腮。因为项目用的spring boot。如果了解他们的本质就会知道可以直接自己这样写。

方法三:BeanFacoty registerSingleton

先上代码,定义一个普通Bean。

代码语言:javascript
复制
@Data
public class User {
    private Integer id;
    private String name;
    private String password;
    private Integer age;
}

定义一个被spring可以扫描的类,这个类要实现

BeanFactoryPostProcessor。里面调用registerSingleton注册一个对象。

代码语言:javascript
复制
@Component
public class MyBeanFacoty implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        User user1 = new User();
        user1.setId(1);
        user1.setName("贾元春");
        user1.setAge(27);
        configurableListableBeanFactory.registerSingleton("user", user1);
    }

}

之后就可以随时进行依赖了。

代码语言:javascript
复制
@RestController
public class JacksonController {
    @Resource
    private User user;
    @GetMapping("/writeStringAsString")
    public String writeStringAsString(String toWrite) throws Exception {
        System.out.println(user.getAge());
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.writeValueAsString(toWrite);
    }

这时候大家是否会有个疑问,XML配置Bean是传统的spring mvc里常用的将对象交给spring来管理的方法,@Bean是spring boot里将对象交给spring来管理的方法。那为什么还要有这个先实现BeanFactoryPostProcessor的方法呢?

因为这种方法可以用来做这件事情,但是不仅仅可以做这件事情。它神通广大,不仅可以将一个对象交给spring管理,还可以将已经交给spring管理的对象拿出来进行修改,还有其他各种的spring初始化的干预都可以做。所以用它来仅仅注册一个Bean有点杀鸡用牛刀的味道。

总结思考

之前也写过一些spring的文章,如:

SpringBoot启动原理

学习Spring的思考框架

专治不会看源码的毛病--spring源码解析AOP篇(2017版)

SpringBoot优雅退出

你看不懂的spring原理是因为不知道这几个概念

Spring参数的自解析--还在自己转换?你out了!

这些文章主要围绕的核心就是spring framework的原理和spring看似基础的应用技巧。

这是我的一个理念。学spring和学厨师很像。基础就是刀工、材料和火候。掌握了基础,通过自己的悟性就可以千变万化了。悟性不是靠教的,有用的还是基础。

spring有很多的扩展内容,spring boot、spring cloud、spring batch。之所以有这些就是因为它做了两件事:第一是控制反转,使用Bean的时候随时取用;第二是aop,把那些可以重用的代码写一份想用的地方都可以生效。

刚毕业的时候,有大师教我们说控制反转和依赖注入是一回事,后来我想想其实不是。控制反转是把对象和类交给spring来管理,由spring来控制器生命周期的过程。依赖注入是在使用对象的时候,可以通过set、构造器和注解方式获取对象的过程。一个是存钱的过程,一个是取钱的过程。联系是存钱是为取钱服务的。

而spring的一些高级框架就是将更多的东西交给spring来管理的过程,比如spring-jdbc,就是通过spring容器就可以调用jdbc了。我个人认为原理了解了,学的价值不大。

spring作者是学音乐出身的。spring牛的地方是它的理念,它没有做什么事情,只是把能替程序员做的事情都做了,给程序员开发带来了春天。把开发变成了艺术。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-08-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringBoot启动原理
  • 学习Spring的思考框架
  • 专治不会看源码的毛病--spring源码解析AOP篇(2017版)
  • SpringBoot优雅退出
  • 你看不懂的spring原理是因为不知道这几个概念
  • Spring参数的自解析--还在自己转换?你out了!
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档