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 就会抛出异常,为了避免异常的出现,你可以将 @Autowiredrequired 属性设置为 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 的装配方式的更多相关文章

  1. Spring 中Bean的装配方式

    最近又买了一本介绍SSM框架的书,是由黑马程序员编写的,书上讲的很好理解,边看边总结一下.主要总结一下bean的装配方式. Bean的装配可以理解为依赖系统注入,Bean的装配方式即Bean依赖注入的 ...

  2. 【Spring】Spring中的Bean - 5、Bean的装配方式(XML、注解(Annotation)、自动装配)

    Bean的装配方式 简单记录-Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)-Spring中的Bean 文章目录 Bean的装配方式 基于XML的装配 基于注解 ...

  3. Bean的装配方式

    (一) 知识点:Spring容器支持多种形式的Bean的装配方式,比如基于XML的装配,基于注解的装配和自动装配(最常用的就是基于注解的装配) Spring提供了两种基于xml的装配方式:设值注入(S ...

  4. bean的装配方式(注入方式,构造注入,setter属性注入)

    bean的装配方式有两种,构造注入和setter属性注入. public class User { private String username; private String password; ...

  5. Spring -bean的装配和注解的使用

    一,bean的装配 bean是依赖注入的,通过spring容器取对象的. 装配方法有: 前面两种没什么好讲的,就改改参数就好了. 这里重要讲注解. 注解的主要类型见图,其中component是bean ...

  6. Spring———bean的创建方式,注入方式,复杂类型注入 概括

    Spring相关概念和类    1.IOC             inverse of control    控制反转   反转了创建对象的方式            以前:new 对象,管理和维护 ...

  7. Spring Bean的装配

    Bean 的装配,即Bean对象的创建.容器根据代码要求创建Bean对象后再传递给代码的过程,称为Bean的装配. 一.默认分的装配方式 默认的装配的方式调用Bean类的构造方法 二.动态工厂Bean ...

  8. Spring bean实例化的方式

    实例化过程如图,方式如图. 甩代码. 方式一:构造方法 搞一个bean,修改一下xml配置 package com.itheima.instance.constructor; public class ...

  9. spring——bean自动装配

    注意:自动装配功能和手动装配要是同时使用,那么自动装配就不起作用. beans.xml <?xml version="1.0" encoding="UTF-8&qu ...

随机推荐

  1. Android零基础入门第65节:RecyclerView分割线开发技巧

    在上一期通过简单学习,已经领略到了RecyclerView的灵活性,当然都是一些最基础的用法,那么本期一起来学习RecyclerView的分割线使用. 相信有的比较细心的同学已经发现了,使用Recyc ...

  2. B/s发展情况真的可以用日新月异来形容

    做c/s也做b/s.从发展情况看,B/s发展情况真的可以用日新月异来形容,但确实也有些绕着路走的框架,不如delphi层次结构清晰. 如果前端用过angularjs等类似框架,则已经相当接近c/s的水 ...

  3. Qt学习虚拟机--基于MSYS2-MinGW环境并带有各种开源的软件库!

    Qt学习虚拟机--基于MSYS2-MinGW环境并带有各种开源的软件库!虚拟机地址,VM10和以上:http://pan.baidu.com/s/1slcTA49包含两个分卷压缩包,加起来5GB多. ...

  4. ngnix 安装

    1安装PCRE库 ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ 下载最新的 PCRE 源码包,使用下面命令下载编译和安装 PCRE 包: ...

  5. .NET中扩展方法和Enumerable(System.Linq)

    LINQ是我最喜欢的功能之一,程序中到处是data.Where(x=x>5).Select(x)等等的代码,她使代码看起来更好,更容易编写,使用起来也超级方便,foreach使循环更加容易,而不 ...

  6. Redis 学习笔记(篇一):字符串和链表

    本次学习除了基本内容之外主要思考三个问题:why(为什么).what(原理是什么).which(同类中还有哪些类似的东西,相比有什么区别). 由于我对 java 比较熟悉,并且 java 中也有字符串 ...

  7. Docker环境下的前后端分离项目部署与运维(十一)Docker Swarm技术

    Docker Swarm技术 docker swarm技术(之前的docker集群都是在 一个虚拟主机上的,但是如果这个主机挂掉了over了,docker技术就是多个虚拟主机形成一个集群) Swarm ...

  8. java 字节码指令集

    This is a list of the instructions that make up the Java bytecode, an abstract machine language that ...

  9. 使用docker部署zabbix

    1 官方地址 官方写的很详细并且是中文的,一步步按照操作就可以 https://www.zabbix.com/documentation/3.4/zh/manual/installation/cont ...

  10. kuberbetes基础概念

    部署了一大堆,来了解一下K8S一些基本的概念. 1.Node Node作为集群中的工作节点,运行真正的应用程序,在Node上Kubernetes管理的最小运行单元是Pod.Node上运行着Kubern ...