Spring Bean 的装配方式
Spring Bean 的装配方式
装配 Bean 的三种方式
一个程序中,许多功能模块都是由多个为了实现相同业务而相互协作的组件构成的。而代码之间的相互联系又势必会带来耦合。耦合是个具有两面性的概念,高度的耦合会导致代码难以复用,难以测试,难以理解;但同时耦合又是必须的,不耦合的代码什么也做不了。
在 Spring
中,容器负责了把需要相互协作的对象引用赋予各个对象,对象无需自己查找或创建与其相关联的对象。而创建应用对象之间的协作称之为装配(wiring
),也就是依赖注入(DI
)的本质。
在 Spring
中装配 Bean
有以下三种常见的方式:
- 在 XML 中进行显示配置;
- 在 Java 代码中显示配置;
- 隐式的 Bean 发现机制和自动装配;
自动化装配 Bean
三种装配方式中,最常用最高效的就是自动化装配了,Spring 从两个角度来实现自动化装配:
- 组件扫描(
component scanning
):Spring 会自动发现应用上下文中所创建的 Bean。 - 自动装配(
autowiring
):Spring 自动满足 Bean 之间的依赖。
以我们平时代码中的三层架构举例,首先创建一个 Dao 层的接口类和实现类
接口类
@Repository
public interface UserDao {
/**
* 根据 Username 和 password 查找 User 对象
* @param usernmae 账号名称
* @param password 账户密码
* @return User
*/
public User getUser(String Username, String password);
}
实现类
public class UserDaoImpl implements UserDao {
public User getUser(String email, String password) {
// do something...
return user;
}
}
然后当我们在 Service 层需要调用到上面 Dao 层的实例化对象时,我们只需要简单声明一个对应的类,并上标注解即可
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
@Override
public User login(String email, String password) {
return userDao.getUser(email, password);
}
}
之后,你还需要在配置文件中启动组件扫描。在 spring-context.xml
文件中(或者这个文件在你项目中叫其他名字,无所谓)配置 <context:component-scen>
元素。
<context:component-scan base-package="yourpackage" />
当然,这里你也不一定只能通过 xml 文件形式来配置,也可以通过基于 Java 的配置。
@Configuration
@CompomentScan(basePackages = "yourpackage")
public class BeanConfig {}
现在这段代码应该就能发挥它的实际用途了。
回顾刚刚的代码,可以发现有 @Repository
、 @Autowired
这两个注解。当你声明一个 Bean 的时候,你需要在类上使用相应的注解来让 Spring 的上下文找到这个类,类似于 Repository
, Spring 中还提供了 3 个功能基本等效的注解:
@Repository
:用于对 DAO 的实现类进行注解;@Service
:用于对 Service 的实现类进行注解;@Controller
:用于对 Controller 的实现类进行注解;@Component
:用于注解一些工具类或其他不归与上述类别的组件。
而当你需要引入一个 Bean 时,@AutoWired
就可以将 Bean 注入到代码中。
不过 @AutoWired
注解不仅能够用在构造器上,还能用在属性的 Setter
方法上,如下面代码所示
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
不过实际上 Setter 方法没有任何特殊之处,@Autowried
注解可以用在类的任何方法上。
但是不管是构造器,Setter 方法还是其他的方法,Spring 都会尝试满足方法参数上所声明的依赖。假如有且只有一个 Bean 匹配依赖需求的话,那么这个 Bean 将会被装配进来。
如果没有匹配的 Bean,那么在应用上下文创建的时候,Spring 就会抛出异常,为了避免异常的出现,你可以将 @Autowired
的 required
属性设置为 false
。
@Autowired(required = false)
UserDao userDao;
将 required
属性设置为 false
时, Spring 依旧会尝试进行自动装配,但是如果没有匹配到 Bean 的话,Spring 会将这个处于未装配状态。不过我们在实际开发中,毕竟我们不大可能引入一个后面代码没有引用到的对象,而这可能让你的程序报空指针异常。
@Auowried
注解是通过 byType
方式注入的,如果环境中不止匹配到两个 Bean 时,或许你该给你的 Bean 进行命名,然后在 @Qualifier
的属性中指向该 Bean 的名称。
@Component("beanName")
public class Bean {
// write something
}
@Autowried
@Qualifier("beanName")
Bean bean;
通过 Java 代码配置 Bean
通过 Java 代码配置 Bean 的方式在理解起来要简单明了许多,而且这种方式也有其特定的应用场景,比如说你要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加 @Component
或者其他注解的,因此就不能使用自动化装配的方案了。所以在这种情况下,显示装配就成了新的选择,下面我们先来了解下如何通过 Java 代码配置 Bean。
创建配置类
@Configuration
public class BeanConfig {
}
@Configuration
注解表明这个类是一个配置类,之后我们将在该类中配置 Spring 应用上下文中如何创建类的细节。
声明 Bean
然后在配置类中声明要配置 Bean,我们需要编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加 @Bean
注解,同时也可以通过 name 属性指定一个不同的名字,当然不写也没问题。例如下面代码
@Bean(name = "beanName")
public Bean bean {
return new Bean();
}
假如你需要另外一个 Bean 作为你创建这个 Bean 的参数的话,你也可以通过下面的方式进行配置
public Bean bean(AnotherBean anotherBean) {
return new Bean(anotherBean);
}
之后的事情就交给 Spring 去完成吧,你依旧可以像前面提及的方式去进行依赖注入。
通过 XML 装配 Bean
在我们项目开发中,我们可以发现,通过注解和 Java 配置文件装配 Bean,最大的好处就是配置方便,直观等等,但是其弊端也显而易见,以硬编码的方式写入到 Java 代码中,当修改其中的代码时,是需要重新编译的。
XML 相对起前面两种方式,也有其相应的利弊。最大的好处莫过于对其做修改,无需编译代码,只需要重启程序即可加载新的配置。下面就来介绍下通过 XML 配置装配 Bean。
创建 XML 配置规范
如代码所示
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- congifuration here ... -->
</beans>
声明 <bean>
<bean id="beanName" class="package.Bean">
这里声明了一个很简单的 Bean,创建这个 Bean 的类通过 class
属性来指定的,并且要使用权限定的类名。同时也要给 bean 声明一个 ID,当然你在这里不声明也没什么问题,bean 本身会自动得到一个 ID 名 package.Bean#0
。不过你之后也可能会引用到这个 Bean,所以就加个 ID 咯。
到这里,其实 XML 的配置已经完成了,你可以在你的代码中进行依赖注入了。但是我们的对象初始化的时候,我们可能还要注入一些属性。在 Spring 中,当发现到 <bean>
元素时,会调用这个元素中指向的类的默认构造函数来创建 bean。在 XML 的配置中,没法像 Java Config 那样灵活地配置。接下来就介绍如何在初始化 Bean 时注入属性
借助构造器注入初始化 Bean
当你采用构造器注入时,有两种基本的配置方案可供选择:
<constructor-arg>
元素- 使用 c- 命名空间(只适用 Spring 3.0 后的版本)
下面举例采用 <constructor-arg>
元素:
<bean id="beanName" class="package.Bean">
<constructor-arg ref="beanName2" />
</bean>
这样,当 Spring 遇到这个 元素时,他会创建一个 Bean 实例。<constructor-arg>
元素会告知 Spring 将一个 ID 为 beanName2 的 bean 引用传递到 Bean 的构造器中。
装配字面量以及集合
我们也可以将字面量注入构造器中,我们先创建一个 Bean3 类
public class Bean3 {
String str1;
String str2;
public Bean3(String str1, String str2) {
this.str1 = str1;
this.str2 = str2;
}
public void log() {
sout(str1 + " " + str2);
}
}
然后再在 xml 文件中进行以下配置
<bean id="beanName3" class="package.Bean3">
<constructor-arg value="hello" />
<constructor-arg value="world" />
</bean>
接下来介绍下如何装配集合,其实只需要简单在 <constructor-arg>
中声明集合即可,如下所示:
<constructor-arg>
<list>
<value>str1</value>
<value>str2</value>
</list>
</constructor-arg>
-----------------------------------------------
<constructor-arg>
<list>
<ref bean="beanName" />
<ref bean="beanName" />
<ref bean="beanName" />
</list>
</constructor-arg>
设置属性值
假设我们现在有这么一个类,没有任何的构造器(除了隐式的构造器),它没有任何的强依赖。
public void TestBean {
private String str1;
private List<String> strList;
// set()...
public void log() {
sout(str1);
fore strList {
sout(strList + " ");
}
}
}
就如上面类所示,它并不强制我们装配任何的属性,但是当你不设置属性属性去调用 log() 方法的时候,毫无疑问会报空指针异常。所以,我们要设置这些属性,可以借助 property
元素的 value
属性实现该功能
<bean id="testBean" class="package.TestBean">
<property name="str1" value="hello" />
<property name="strList">
<list>
<value>world</value>
<value>and</value>
<value>spring</value>
</list>
</property>
</bean>
这样就可以实现将量注入 bean 中了。
小结
Spring 有多种方案来配置 Bean,这给我们提供了许多解决问题的思路,Spring 的配置也是可以相互搭配的,就像我们热衷与使用自动装配,但是有时 xml 装配或者 Java Config 装配才是最优的选择,这取决我们工作中遇见的情况。
顺带一提,若注解与 XML 同时使用,XML 的优先级要高于注解。这样做的好处是,需要对某个 Bean 做修改,只需要修改配置文件即可。
Spring Bean 的装配方式的更多相关文章
- Spring 中Bean的装配方式
最近又买了一本介绍SSM框架的书,是由黑马程序员编写的,书上讲的很好理解,边看边总结一下.主要总结一下bean的装配方式. Bean的装配可以理解为依赖系统注入,Bean的装配方式即Bean依赖注入的 ...
- 【Spring】Spring中的Bean - 5、Bean的装配方式(XML、注解(Annotation)、自动装配)
Bean的装配方式 简单记录-Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)-Spring中的Bean 文章目录 Bean的装配方式 基于XML的装配 基于注解 ...
- Bean的装配方式
(一) 知识点:Spring容器支持多种形式的Bean的装配方式,比如基于XML的装配,基于注解的装配和自动装配(最常用的就是基于注解的装配) Spring提供了两种基于xml的装配方式:设值注入(S ...
- bean的装配方式(注入方式,构造注入,setter属性注入)
bean的装配方式有两种,构造注入和setter属性注入. public class User { private String username; private String password; ...
- Spring -bean的装配和注解的使用
一,bean的装配 bean是依赖注入的,通过spring容器取对象的. 装配方法有: 前面两种没什么好讲的,就改改参数就好了. 这里重要讲注解. 注解的主要类型见图,其中component是bean ...
- Spring———bean的创建方式,注入方式,复杂类型注入 概括
Spring相关概念和类 1.IOC inverse of control 控制反转 反转了创建对象的方式 以前:new 对象,管理和维护 ...
- Spring Bean的装配
Bean 的装配,即Bean对象的创建.容器根据代码要求创建Bean对象后再传递给代码的过程,称为Bean的装配. 一.默认分的装配方式 默认的装配的方式调用Bean类的构造方法 二.动态工厂Bean ...
- Spring bean实例化的方式
实例化过程如图,方式如图. 甩代码. 方式一:构造方法 搞一个bean,修改一下xml配置 package com.itheima.instance.constructor; public class ...
- spring——bean自动装配
注意:自动装配功能和手动装配要是同时使用,那么自动装配就不起作用. beans.xml <?xml version="1.0" encoding="UTF-8&qu ...
随机推荐
- Xdite:永葆热情的上瘾式学习法(套路王:每天总结自己,反省自己的作息规律,找到自己的幸运时间、幸运方法,倒霉时间、倒霉方法。幸运是与注意力挂钩的。重复才能让自己登峰造极,主动去掉运气部分来训练自己。游戏吸引自己的几个原因非常适合训练自己)good
版权声明 本文首发自微信公共帐号: 学习学习再学习(xiaolai-xuexi) 无需授权即可转载, 甚至无需保留以上版权声明: 转载时请务必注明作者. 以下是<共同成长社区>第 58 次 ...
- 解决手机提示TF卡受损需要格式化问题
昨晚因为上QQ FOR PAD后.关机.结果又杯具了.上次无意看到一个SD卡修复命令,收藏起来了.一试,还真管用.现把它写出来.分享给大家.以后出现SD卡受损,千万不要再格式化内存卡了.修复过程:1. ...
- Android零基础入门第56节:翻转视图ViewFlipper打造引导页和轮播图
原文:Android零基础入门第56节:翻转视图ViewFlipper打造引导页和轮播图 前面两期学习了 ViewAnimator及其子类ViewSwitcher的使用,以及ViewSwitcher的 ...
- SQL Server中 SET 和 SELECT 赋值有什么区别?
SQL Server 中对已经定义的变量赋值的方式用两种,分别是 SET 和 SELECT.对于这两种方式的区别,SQL Server 联机丛书中已经有详细的说明,但很多时候我们并没有注意,其实这两种 ...
- chrome 仿手机
很多网站都通过User-Agent来判断浏览器类型,如果是3G手机,显示手机页面内容,如果是普通浏览器,显示普通网页内容. 谷歌Chrome浏览器,可以很方便地用来当3G手机模拟器.在Windows的 ...
- 三种扩展 Office 软件功能的开发模型对比 – Office Add-In Model, VBA 和 VSTO
当 Office 用户需要针对文档自定义新功能时,可以求助于 VBA 或者 VSTO 两种方式.Office 2013 富客户端以后,微软为 Office 平台上的开发者提供了一种新模型 --- Of ...
- Unity 入門 - 延遲解析
本文大纲: 小引 共享的范例代码 使用 Lazy<T> 使用自动工厂 注入自定义工厂 小引 当我们说「解析某个型别/组件」时,意思通常是呼叫某类别的建构函式,以建立其实例(instance ...
- Python连载9-setup环境变量&os模块
一.timeit包(上接连载9) 1.我们对于timeit函数,可采取如下例子: h = ''' def doTt(num1): for i in range(num1): print(i) ''' ...
- MySQL之SQL优化详解(三)
目录 MySQL 之SQL优化详解(三) 1. 索引优化 2. 剖析报告:Show Profile MySQL 之SQL优化详解(三) 1. 索引优化 一旦建立索引,select 查询语句的where ...
- .NET架构开发应知应会
.NET程序是基于.NET framework..NET Core.Mono.UWP[.NET实现]开发和运行的 ,定义以上[.NET实现]的标准规范称为.NET Standard L1:.NET S ...