背景
先说一说什么叫把对象交给spring管理。它区别于把类交给spring管理。在spring里采用注解方式@Service、@Component这些,实际上管理的是类,把这些类交给spring来负责实例化。
而对象交给spring管理,举个例子,最常见的在配置文件里定义一个bean,或者JavaConfig的方式就是在@Configure标签标注的类里的@Bean对象。这些Bean已经new出来了。是以对象实例的方式交给spring管理的。这些对象往往是与业务无关的基础组件。比如datasource的bean、redis连接池的bean。个数是有限的。
特别是面试的时候千万要注意他们的区别。有时候有的人觉得自己回答没问题,最后面试没通过,很可能是因为没有弄清楚面试的考察点。面试官的逻辑是如果你没弄清楚问题就回答,面试官很可能会怀疑工作中接到任务也会没有弄清楚就直接开干,做出些负产出来。建议面试的时候不但回答问题,同时也可以说对象交给spring管理和类交给spring管理有点类似,但是……这样清楚的表达自己的思考。
开始之前,记得点赞收藏加关注哦 ,我这里也准备了很多面试热门知识点和大厂面试题,希望对大家有帮助!有需要的朋友
可以加q群:580763979 备注:简书 免费领取~
这个方法非常常见,举个例子:
<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工具发布了,成本工作量是一样的。但是这样写,能明确修改的是配置,不是代码逻辑。影响范围会更明确些。
这个方法是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。
@DatapublicclassUser{privateInteger id;privateString name;privateString password;privateInteger age;}
定义一个被spring可以扫描的类,这个类要实现
BeanFactoryPostProcessor。里面调用registerSingleton注册一个对象。
@ComponentpublicclassMyBeanFacotyimplementsBeanFactoryPostProcessor{@OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)throwsBeansException{User user1=newUser();user1.setId(1);user1.setName("贾元春");user1.setAge(27);configurableListableBeanFactory.registerSingleton("user",user1);}}
之后就可以随时进行依赖了。
@RestControllerpublicclassJacksonController{@ResourceprivateUser user;@GetMapping("/writeStringAsString")publicStringwriteStringAsString(String toWrite)throwsException{System.out.println(user.getAge());ObjectMapper objectMapper=newObjectMapper();returnobjectMapper.writeValueAsString(toWrite);}
这时候大家是否会有个疑问,XML配置Bean是传统的spring mvc里常用的将对象交给spring来管理的方法,@Bean是spring boot里将对象交给spring来管理的方法。那为什么还要有这个先实现BeanFactoryPostProcessor的方法呢?
因为这种方法可以用来做这件事情,但是不仅仅可以做这件事情。它神通广大,不仅可以将一个对象交给spring管理,还可以将已经交给spring管理的对象拿出来进行修改,还有其他各种的spring初始化的干预都可以做。所以用它来仅仅注册一个Bean有点杀鸡用牛刀的味道。
这些文章主要围绕的核心就是spring framework的原理和spring看似基础的应用技巧。
这是我的一个理念。学spring和学厨师很像。基础就是刀工、材料和火候。掌握了基础,通过自己的悟性就可以千变万化了。悟性不是靠教的,有用的还是基础。
spring有很多的扩展内容,spring boot、spring cloud、spring batch。之所以有这些就是因为它做了两件事:第一是控制反转,使用Bean的时候随时取用;第二是aop,把那些可以重用的代码写一份想用的地方都可以生效。
刚毕业的时候,有大师教我们说控制反转和依赖注入是一回事,后来我想想其实不是。控制反转是把对象和类交给spring来管理,由spring来控制器生命周期的过程。依赖注入是在使用对象的时候,可以通过set、构造器和注解方式获取对象的过程。一个是存钱的过程,一个是取钱的过程。联系是存钱是为取钱服务的。
而spring的一些高级框架就是将更多的东西交给spring来管理的过程,比如spring-jdbc,就是通过spring容器就可以调用jdbc了。我个人认为原理了解了,学的价值不大。
spring作者是学音乐出身的。spring牛的地方是它的理念,它没有做什么事情,只是把能替程序员做的事情都做了,给程序员开发带来了春天。把开发变成了艺术。
我这里也准备了一线大厂面试资料和超多超硬核的PDF技术文档,以及我为大家精心准备的多套简历模板(不断更新中),希望大家都能找到心仪的工作!
有需要的朋友可以加q群:580763979 备注:简书 免费领取~
网友评论