把对象交给spring管理的3种方法及经典应用
背景
先说一说什么叫把对象交给spring管理。它区别于把类交给spring管理。在spring里采用注解方式@Service、@Component这些,实际上管理的是类,把这些类交给spring来负责实例化。
而对象交给spring管理,举个例子,最常见的在配置文件里定义一个bean,或者JavaConfig的方式就是在@Configure标签标注的类里的@Bean对象。这些Bean已经new出来了。是以对象实例的方式交给spring管理的。这些对象往往是与业务无关的基础组件。比如datasource的bean、redis连接池的bean。个数是有限的。
特别是面试的时候千万要注意他们的区别。有时候有的人觉得自己回答没问题,最后面试没通过,很可能是因为没有弄清楚面试的考察点。面试官的逻辑是如果你没弄清楚问题就回答,面试官很可能会怀疑工作中接到任务也会没有弄清楚就直接开干,做出些负产出来。建议面试的时候不但回答问题,同时也可以说对象交给spring管理和类交给spring管理有点类似,但是……这样清楚的表达自己的思考。
方法一:XML配置Bean
这个方法非常常见,举个例子:
<bean id="car" class="com.lm.spring.bean.Car">
这种定义方法相当于Car car = new Car() 然后 注册car到spring容器。用的时候直接用。
既然bean是被实例化后的对象,就涉及到对象实例化的时候要传参数的问题。
<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。
<!-- 数据源配置 -->
<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>
这些都是常规用法。前段时间见到了另外一种用法,虽然没啥技术难度。确实之前没有这么用过,也觉得很有意思:
<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配置文件的方法都可以用这个方法改写。
@Configuration //此处为配置项
public class ServiceConfig {
@Bean //此处返回的是一个Spring的配置Bean,与xml的<bean>等价
public IMessageService getMessageService() {//方法名称随便写
return new MessgeServiceImpl();
}
}
很多基础组件的使用文档提供的是XML配置形式的,看到过一些刚毕业的同学在抓耳挠腮。因为项目用的spring boot。如果了解他们的本质就会知道可以直接自己这样写。
方法三:BeanFacoty registerSingleton
先上代码,定义一个普通Bean。
@Data
public class User {
private Integer id;
private String name;
private String password;
private Integer age;
}
定义一个被spring可以扫描的类,这个类要实现
BeanFactoryPostProcessor。里面调用registerSingleton注册一个对象。
@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);
}
}
之后就可以随时进行依赖了。
@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牛的地方是它的理念,它没有做什么事情,只是把能替程序员做的事情都做了,给程序员开发带来了春天。把开发变成了艺术。
把对象交给spring管理的3种方法及经典应用的更多相关文章
- Spring管理事物两种方式
Spring管理事物两种方式 1. 编程式事物管理(在开发中不经常使用) 使用步骤 1. 配置数据库事物管理 DataSourceTransactionManager <!--配置事物管理器-- ...
- 使用Spring Security3的四种方法概述
使用Spring Security3的四种方法概述 那么在Spring Security3的使用中,有4种方法: 一种是全部利用配置文件,将用户.权限.资源(url)硬编码在xml文件中,已经实现过, ...
- javascript获取json对象的key名称的两种方法
javascript获取json对象的key名称的两种方法 数据处理中,你可能接收到一个不确定内容格式的json对象,然后要把key的值提取出来.今天试过两种可以提取json key的方法,均可以正常 ...
- js对象之间的"继承"的五种方法
今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动物"对象的构造函数. function Animal(){ this.species = & ...
- strut1.X和spring整合的二种方法
第一种集成方法 原理:在Action中取得BeanFactory对象,然后通过BeanFactory获取业务逻辑对象 缺点:产生了依赖,spring的类在action中产生了依赖查找.(注意和依赖注入 ...
- Spring实例化Bean三种方法:构造器、静态工厂、实例工厂
Spring中Bean相当于java中的类,可以通过xml文件对bean进行配置和管理. 一.Bean的实例化: 构造器实例化.静态工厂实例化.实例工厂方式实例化. 目录: 构造器实例化: xml配置 ...
- Spring创建对象的几种方法
一.通过构造器 无参构造器 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=" ...
- js中控制流管理的四种方法
引自http://es6.ruanyifeng.com/#docs/generator#yield--表达式 1.常用的回调方法 step1(function (value1) { step2(val ...
- java对象转换String类型的三种方法
在很多情况下我们都需要将一个对象转换为String类型.一般来说有三种方法可以实现:Object.toString().(String)Object.String.valueOf(Object).下面 ...
随机推荐
- ClouderaManager安装kafka报错
是因为默认的java heap size是50M,将broker_max_heap_size参数设置为512M后,重启kafka服务即可
- Java线程池中的核心线程是如何被重复利用的?
真的!讲得太清楚了!https://blog.csdn.net/MingHuang2017/article/details/79571529 真的是解惑了 本文所说的"核心线程". ...
- Exception 和Error异常大部分人都犯过的错。
先看再点赞,给自己一点思考的时间,如果对自己有帮助,微信搜索[程序职场]关注这个执着的职场程序员. 我有什么:职场规划指导,技能提升方法,讲不完的职场故事,个人成长经验. 1,简介 Exception ...
- linux驱动之LED驱动
通过之前的学习,了解到linux驱动编写的流程是:先通过注册函数注册我们编写的入口函数,然后在入口函数中获取设备号->注册字符设备->自动创建设备节点->获取设备树信息,最后通过销毁 ...
- C#版Nebula客户端编译
一.需求背景 从Nebula的Github上可以发现,Nebula为以下语言提供了客户端SDK: nebula-cpp nebula-java nebula-go nebula-python nebu ...
- es-head部署
#一.更新centos7的库sudo yum update -y二.安装一系列文件(已安装可以不安装)sudo rpm -ivh http://dl.fedoraproject.org/pub/epe ...
- 一行代码打印python之禅
就这一句: import this 输出: The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is be ...
- 手写系列-实现一个铂金段位的 React
一.前言 本文基于 https://pomb.us/build-your-own-react/ 实现简单版 React. 本文学习思路来自 卡颂-b站-React源码,你在第几层. 模拟的版本为 Re ...
- Kafka之--多zookeeper,多broker之搭建
闲来如事,突发兴趣倒腾一下了kafka.其实类似环境搭建的博客很多,我这里算是整合一下,另外写出自己的过程与看法.完整的过程如下: 1)先准备好3台服务器.我准备的机器hostname/ip为: ka ...
- 02_Java基础类型和包装类型
基本数据类型 包装类名称 所占字节数 默认值 byte Byte 1 0 short Short 2 0 Int Integer 4 0 long Long 8 0L double Double 8 ...