读Spring实战(第四版)概括—装配Bean

2024-09-08 09:58

本文主要是介绍读Spring实战(第四版)概括—装配Bean,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

很久很久以前读过Spring实战(第三版),因为第三版和第四部差异还是特别明显的,在整体思想上有了比较重大的改变,比如用注解和JavaConfig替换Xml以及现在非常火热的Springboot在书的最后也有提到。OK,开始看书,书本的第一章讲了一下Spring存在的目的(简化Java开发)和Spring的功能,以及Spring3->Spring4增加了哪些功能,那我就从第二章开始概括本书,以给我自己后面快速回忆使用。

在Spring中,对象无需自己查找或者创建与其所关联的其他对象。相反容器负责把需要相互协作的对象引用赋予各个对象。创建应用对象之间协作关系的行为通常被称为装配(wiring),这也是依赖注入(DI)的本质。

1.Spring配置的可选方案

当描述bean如何装配时,Spring具有非常大的灵活性,它提供了三种主要的装配机制:

  • 在XML中进行显示配置
  • 在Java中进行显示配置
  • 隐式的Bean发现机制和自动装配

我建议尽可能的使用自动配置的机制。显示配置越少越好。如果必须要使用显示配置,我推荐使用类型安全并且比XML更加强大的JavaConfig,最后在使用XML配置。

2.自动化装配Bean

Spring从两个角度来实现自动化装配:

  • 组件扫描(component scanning):Spring会发现应用上下文中所创建的Bean
  • 组件装配(autowiring):Spring自动满足Bean之间的依赖

组件扫描和自动装配组合一起就能发挥强大的威力,他们能够将你的显示配置降低到最小。

实现自动化装配有两种方式:(组件扫描默认是不启动的)

1)通过XML启用组件扫描

首先在mvc-config.xml中启动组件扫描功能,并用base-package属性指定扫描范围

<context:component-scan base-package="com.wxh.controller"/>

再通过在需要注解的class上添加@Controller@Service、@Repository、@Component等注解,比如:

@Controller
public class UserController {// ......}

2)通过@ComponentScan注解启用组件扫描

首先在class上使用@ComponentScan启用组件扫描,例如:

@ComponentScan
public class AppConfig {// ......}

此外:@ComponentScan(basePackages="conf")等同于@ComponentScan("conf"),然后通过在需要注解的class上添加@Controller@Service、@Repository、@Component等注解,例如:

@Controller
public class UserController {// ......}

对于@ComponentScan可以通过basePackages或者basePackageClasses指定扫描范围,等同于XML注解中的base-package属性;如果不指定扫描范围,则默认扫描当前类所在包以及子包的所有类。当然Craig Walls建议使用basePackageClasses因为如果代码重构的话这种方式会立马发现错误,下面是basePackageClasses的使用方式(指定基础扫描类):

@ComponentScan(basePackageClasses={UserController.class// ......
})
public class AppConfig {}

使用@Autowired可以为bean实现自动装配,@Autowired可以使用在构造函数、Setter方法、普通方法和成员变量上。比如下面的用法:

// 用法一:
@Autowired
MessageSend messageSend;
// 用法二:(构造函数也一样,主要是函数参数的依赖)
@Autowired
public void setMessageSend(MessageSend messageSend) {this.messageSend = messageSend;
}

设置@Autowired(required=false)时,Spring尝试执行自动装配,但是如果没有匹配的bean则忽略,但是这种情况故意出现空指针异常NullPointerException。@Autowired注解可以使用@Inject替换,@component可以使用@Named注解替换,后者是源于Java依赖注入规范。

3.通过Java代码装配

大部分的场景自动化装配Bean是满足要求的,但是在一些特殊场景下自动化装配Bean是无法满足要求的,比如说要将第三方的组件装配到自己的应用中,因为没有方法将@component或者@Autowired注解放置在它们的类上。但是你仍然可以采用显示装配方式:Java代码装配和XML配置。

首先需要创建配置类,创建配置类的关键是使用@Configuration注解来表明这个类是一个配置类,该类包涵Spring上下文中如何创建Bean的细节。

声明一个简单Bean:在Java的配置类中编写一个带有@Bean注解的方法,比如下面:

@Bean
public UserServiceImpl userService(){return new UserServiceImpl();
}

默认情况下Bean的ID是方法名,也可以指定Bean的ID:@Bean(name="userService"),如果有依赖可以使用下面这些的方式来实现:

@Bean
public UserServiceImpl userService(){return new UserServiceImpl(userDao());
}
@Bean
public UserDaoImpl userDao(){return new UserDaoImpl();
}

上面看起来是调用UserDaoImpl(),其实在配置类中Spring会拦截对这个方法的引用,并返回该方法所创建的bean,而不是每次都对其进行实际调用。当然下面这种方式也是可以的,userService()方法需要userDao作为参数,Spring创建Bean的时候会自动装配一个UserDaoImpl到方法中(我猜测应该和@Autowired意思差不多,当Spring Context下只有一个UserDaoImpl就可以通过匹配原则进行装配),这种方式是被推荐的,如果UserDaoImpl不是在本配置类下配置,任然可以正常使用(比如XML默认的组件扫描等)。

@Bean
public UserServiceImpl userService(UserDaoImpl userDao){return new UserServiceImpl(userDao);
}

上面我们通过构造函数的方式实现依赖注入(DI),当然我们也可以用一种更好的方式来实现依赖注入,就是用Setter方法注入,如下所示:

@Bean
public UserServiceImpl userService(UserDaoImpl userDao){UserServiceImpl userService = new UserServiceImpl();userService.setDao(userDao);return userService;
}

上面两种,通过JavaConfig或者自动化装配Bean在SpringBoot会被大量推荐使用,下面的XML模式的装配Bean已经不被推荐使用了。

4.通过XML装配Bean

XML装配Bean的方式,虽然已经不推荐了,但是还是我们最早使用的一种Bean装配的方式,还是需要学习的(很多古老的项目还在用,我目前的公司也是)。下面是一个简单Bean的声明:

<bean id="myFile" class="com.wxh.config.MyFile"></bean>

<Bean>元素类似于配置类中的@Bean,如果没有声明id="myFile",则这个bean的ID则为myFile#0,以此类推是myFile#1、myFile#2......

借助构造器(使用构造函数)注入初始化Bean的方式有两个:

  • <constructor-arg>元素
  • 使用Spring3中引入的c命名空间

如下所示:

<!-- 下面是使用<constructor-arg>元素方式注入Bean -->
<bean id="myFile" class="com.wxh.config.MyFile"><constructor-arg ref="fileProperty"></constructor-arg>
</bean>	
<!-- 下面是使用Spring3.0中引入的c-命名空间方式注入Bean -->
<bean id="myFile-c" class="com.wxh.config.MyFile" 
c:fileProperty-ref="fileProperty" c:count="0"></bean>

上面的两种方式第二张会比较简单,配置代码短,但是风格比较诡异,它的一个解读如下所示:

当然不论是<constructor-arg>元素还是Spring3.0 c-命名空间还可以使用构造器参数位置来注入相应的bean:

<bean id="myFile" class="com.wxh.config.MyFile"><constructor-arg index="0" ref="fileProperty"></constructor-arg><constructor-arg index="1" value="0"></constructor-arg>
</bean>	
<bean id="myFile-c" class="com.wxh.config.MyFile" c:_0-ref="fileProperty" c:_1-ref="0"></bean>

上面说的都是将对象的引用注入到依赖于它们的对象之中,有时候我们也需要一个字面量来配置对象。如下所示(构造函数参数分别是id(int)和name(String)):

<constructor-arg value="101"></constructor-arg>
<constructor-arg value="wuxinhui"></constructor-arg>

对于c标签的使用就不介绍了,个人觉得不如普通的<constructor-arg>元素好用。

有时候,我们需要使用XML对集合的装配。构造函数如下所示(需要装配StringList<String>):

public MyFile(String name, List<String> type) {this.name = name;this.type = type;
}

对于XMl配置,我们可以使用<null/>来传递一个空值给构造器

<bean id="myfile" class="com.wxh.config.MyFile"><constructor-arg value="my.txt"></constructor-arg><constructor-arg><null/></constructor-arg>
</bean>

不过这种方式在使用的时候容易出现空指针异常,所以用下面的方式更好,使用<list>或者<set>元素来传入初始化值:

<bean id="myfile" class="com.wxh.config.MyFile"><constructor-arg value="my.txt"></constructor-arg><constructor-arg><list><value>txt</value><value>doc</value><value>docx</value><!--... 其他格式--></list></constructor-arg>
</bean>
<bean id="myfile" class="com.wxh.config.MyFile"><constructor-arg value="my.txt"></constructor-arg><constructor-arg><set><value>txt</value><value>doc</value><value>docx</value><!--... 其他格式 --></set></constructor-arg>
</bean>

list(java.util.List)和set(java.util.Set)的区别在于set是没有重复值,且无序的。其实就是Java中set和list的区别。

对于类属性的装配:有构造器注入和Setter注入两种;一般强依赖属性使用构造器,可选依赖属性使用Setter注入。对于使用注解来装配属性上面已经阐述过,下面主要说一下Spring XML方式进行属性的注入,如下所示:

<bean id="f" class="com.wxh.config.MyFile"><!-- 属性注入 --><property name="name" value="ceshi.docx"></property><!-- 其他属性 -->
</bean>

或者我们也可以使用p标签来简化属性的注入配置(个人比较推荐,语法比c标签清晰很多),如下:

<bean id="f" class="com.wxh.config.MyFile" p:name="wxk.txt"></bean>

使用util-命令空间中的元素来注入字面量(数组、集合等),下面是Spring util-命名空间中的元素:

元  素

描  述

<util:constant>

引用某个类型的public static域,并将其暴露为bean

<util:list>

创建一个java.util.List类型的bean,其中包含值和引用

<util:map>

创建一个java.util.Map类型的bean,其中包含值和引用

<util:properties>

创建一个java.util.Properties类型的bean

<util:property-path>

引用一个bean的属性(或内嵌属性),并将其暴露为bean

<util:set>

创建一个java.utilSet类型的bean,其中包含值和引用

使用事例如下所示:

<!-- 静态变量 -->
<util:constant static-field="com.wxh.config.MyFile.MAX_SIZE" />
<!-- list -->
<util:list id="list" list-class="java.util.LinkedList"><value>D-1</value><value>D-2</value><value>D-3</value>
</util:list>
<!-- map -->
<util:map id="map"><entry key="数学" value="44" /><entry key="语文" value="77" />
</util:map>
<!-- 加载资源文件 -->
<util:properties id="prop" location="classpath:application.property">
</util:properties>
<!-- 暴露指定bean的属性 -->
<util:property-path path="myfile.name" />
<util:set id="school"><value>小学</value><value>中学</value><value>大学</value>
</util:set>

5.导入和混合配置

在混合配置中,@Autowired自动装配是考虑全局的所有Bean不管XML配置还是JavaConfig注解配置。一般混合配置的使用方式就是:JavaConfig拆分配置、XML拆分配置、JavaConfig配置中引用XML配置、XML中引用JavaConfig配置

5.1.JavaConfig拆分配置

一般如果Bean比较复杂或者逻辑上比较独立,我们为了逻辑上更加清晰,可以将一个JavaConfig拆分成多个。使用@Import注解进行导入,如下所示:

/** AppConfiguration.java */
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.wxh.service" })
@Import(InitJavaConfig.class)
public class AppConfiguration {// 声明的Bean 。。。。。。
}
/** InitJavaConfig.java */
@Configuration
@ComponentScan(basePackages = { "com.wxh.service" })
public class InitJavaConfig {// 声明的Bean 。。。。。。
}

5.2.XML拆分配置

当如果我们使用XML进行Bean的配置,我们有时候为了逻辑更加的清晰,会对XML配置进行拆分。我们可以使用<import>元素来引用其他的XML配置,如下所示可以对拆分的XML进行相互引用:(假如我有一个init-config.xml Bean配置文件)

<import resource="init-config.xml"/>

5.3.JavaConfig配置中引用XML配置

对于使用这种模式的还是比较怪异的,早期我在使用Springboot时,由于不太懂使用注解对Bean配置,用过这种奇特的方式。对于JavaConfig配置中引用XML配置,我们可以使用@ImportResource注解实现,如下使用:

@ContextConfiguration
@Component
@ImportResource("classpath:init-config.xml")
public class AppConfig {// .....
}

5.4.XML中引用JavaConfig配置

对于也是比较奇葩,我目前还没遇到过。不过这种引用JavaConfig配置却更加简单了,只需要使用<bean>标签就可以了。使用如下所示:(AppConfig是使用注释配置的Bean的类)

<bean class="com.test.config.AppConfig"></bean>
总结:只要是拆分的模式,我习惯性的还是会创建一个根配置,这个配置会展现多个装配类或者XML文件或者混合模式。大致的使用方式如下所示(混合模式),Root XML中配置:
<bean class="com.test.config.AppConfig"></bean>
<import resource="init-config.xml"/>

这篇关于读Spring实战(第四版)概括—装配Bean的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147798

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置