参考spring5.1.9文档编写
官网:https://spring.io/projects/spring-framework
Spring概述
spring是什么
Spring是一个轻量级开源框架,是为了解决企业应用开发的复杂性而创建的。Spring 用于整合,好处是解耦。解耦,可以降低组件与组件之间的关联,改善程序结构,便于系统的维护和扩展。
以IOC(控制反转)和AOP(切面编程)为内核。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
一般而言,使用 Spring 框架的主要作用:我们会使用 IoC 整合组件(各种 Bean),使用 AOP 来管理事务。Spring 的使用没有限制,用于 Web 工程还是普通 Java 程序都可以。
JavaEE规范的三层结构体系:
表现层(页面数据显示、页面跳转调度)jsp/servlet
业务层(业务处理和功能逻辑、事务控制)-service
持久层(数据存取和封装、和数据库打交道)dao
Spring特性
IOC(Inversion of Control):即创建被调用的实例不是由调用者完成,而是由Spring容器完成,并注入调用者。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。
AOP(Aspect-Oriented Programming):面向切面编程
容器:spring作为一个容器,包含并管理应用对象的声明周期,对象和对象之间的依赖关系。
轻量:减少开发的复杂度。spring是非侵入性的,基于spring开发的应用中的对象可以不依赖于spring中的api.
一站式:Spring提供了JavaEE各层的解决方案,表现层:Spring MVC,持久层:JdbcTemplate、ORM框架整合,业务层:IoC、AOP、事务控制。在AOP和IOC的基础上,可以整合各个企业应用的开源框架和优秀的第三方类库。
Spring模块
七大核心模块:
核心容器(Spring Core)
核心容器提供Spring框架的基本功能。定义了创建、 配置、和管理bean的方式。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。
应用上下文(Spring Context)
Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring面向切面编程(Spring AOP)
通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
JDBC和DAO模块(Spring DAO)
JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。
对象实体映射(Spring ORM)
Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。
Web模块(Spring Web)
Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
MVC模块(Spring Web MVC)
MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个接口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。
第一个spring程序
spring相关的jar下载地址:https://repo.spring.io
新建工程
创建工程spring01,并添加spring核心jar包,spring框架所需日志包的依赖:
新建接口UserService
publicinterface UserService {
publicvoid add();
}
新建实现类UserServiceImpl
publicclass UserServiceImpl implements UserService{
@Override
publicvoid add() {
System.out.println("add User..");
}
}
新建测试类
不使用spring的方式
publicstaticvoid main(String[] args) {
//常规使用方法,注意此种写法并没有使用到spring
UserService userService = new UserServiceImpl();
userService.add();
}
使用spring
新建applicationContext.xml
<bean id="userService" class="com.niit.service.impl.UserServiceImpl"></bean>
新建测试类
publicstaticvoid main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(“applicationContext.xml”);
UserService userService = (UserService) classPathXmlApplicationContext.getBean(“userService”);//这个名字需要和xml中的名字一致
userService.add();
}
IOC(Inversion of Control)控制反转
其思想是反转资源获取的方向。容器会主动的将资源推送给他所管理的组件,组件要做的是选择一种合适的方式来接收资源。
在类和类之间存在控制权, 控制权指的是对象的创建和使用,比如有类 A 和类 B,我们之前的做法是在 A 中调用 B,那么控制权就在 A 中,这样做的耦合度较高,如果修改了 B, A 也要做相应修改。
引入 Spring 框架后,控制权由 spring 容器来负责。当 A 想使用 B 时,需要由 Spirng 容器通过配置文件进行注入。这种思想就是 IoC(为了更好的理解,我们可以这样认为,对象创建和使用的控制权转移到了 Spring 容器,由 Spring 容器来控制)。
spring提供了两种类型的IOC容器实现:
BeanFactory:IOC容器的基本实现,面向spring本身。参见使用beanfactory实现
ApplicationContext:提供了更多高级的性能,是BeanFactory的子类,面向开发者。参见使用ApplicationContext实现
配置bean
基于XML配置方式
在xml中通过使用节点配置bean,示例如下:
<beanid="userService"class="com.niit.service.impl.UserServiceImpl"></bean>
属性
id: bean的唯一标识
class:指定全类名,以反射的方式创建对象
name:别名
Scope:范围,简单的可以理解成对象在IOC中的生命周期。可选值有六个,参见Scopes。
Constructorarguments:构造器参数
Properties:属性
Autowiringmode:自动装配模式
Lazyinitializationmode:懒加载模式
Initializationmethod:初始化方法:
Destructionmethod:销毁模式
示例:
-
创建类HelloWord.java
publicclass HelloWorld {
private String name ;publicString getName() {
returnname;
}publicvoid setName(String name) {
this.name = name;
}publicvoid sayHello() {
System.out.println("hello: " + name);
}
} -
修改applicationContext.xml
<beanid=“helloWord” class=“com.niit.entity.HelloWorld”>
<propertyname="name"value=“zs”>
-
测试类
方式一(不推荐):使用beanFactory实现
import org.springframework.beans.factory.BeanFactory;
importorg.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import com.niit.entity.HelloWorld;
publicstaticvoid main(String[] args) {
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory xmlBeanFactory = newXmlBeanFactory(resource);//
HelloWorld hw = (HelloWorld) xmlBeanFactory.getBean("helloWord");
hw.sayHello();
}
方式二(推荐):使用ApplicationContext实现
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.niit.entity.HelloWorld;
publicstaticvoid main(String[] args) {
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(“applicationContext.xml”);
HelloWorld hw = (HelloWorld)classPathXmlApplicationContext.getBean("helloWord");
hw.sayHello();
}
基于注解方式
组件扫描:spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件。
特定的组件有:
- 扫描 Bean 组件的注解,替代 xml 中的元素的定义
@Component:组件,受spring管理。
@Respository:持久层组件
@Service:业务层组件
@Controller: 表现层组件
对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写。也可以在注解中通过value属性标识组件的名称。
注意:需要加入aop的包(spring-aop-5.1.9.RELEASE.jar),否则会报错。
-
依赖注入的注解标记
@Resource JDK 提供的。先按类型,后按名称来自劢装配
@AutoWired Spring 提供的,先按名称,后按类型来自劢装配
@Qualifier(“id 名”) -
其他注解
@Scope 等价于
@PostConstruct 等价于
@PreDestroy 等价于
示例
项目结构如下:
- 新建UserController.java, UserService.java, UserDao.java
1)UserController.java
import org.springframework.stereotype.Controller;
@Controller
publicclass UserController {
}
2)UserService.java
import org.springframework.stereotype.Service;
@Service
publicclass UserService {
}
3)UserDao.java
@Repository
publicclass UserDao {
}
- 新建applicationContext.xml
context:component-scanbase-package=“com.demo.spring”</context:component-scan>
-
测试
publicstaticvoid main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(“applicationContext.xml”);
UserController uc = (UserController)ac.getBean(“userController”);
System.out.println(uc);
UserService us = (UserService)ac.getBean(“userService”);
System.out.println(us);
UserDao ud = (UserDao)ac.getBean(“userDao”);
System.out.println(ud);
} -
结果
context:exclude-filter用法
context:exclude-filter表示自动扫描中需要排除的项。
例如:
context:component-scanbase-package=“com.niit.spring”
<context:exclude-filter type="annotation"expression=“org.springframework.stereotype.Repository”/>
<context:exclude-filter type="assignable"expression=“com.niit.spring.controller.UserController”/>
</context:component-scan>
<context:include-filter用法
<context: include-filter>表示自动扫描中需要包含的项。
context:component-scanbase-package="com.niit.spring"use-default-filters=“false”
context:include-filtertype="annotation"expression=“org.springframework.stereotype.Controller”/
<context:include-filtertype="assignable"expression="com.niit.spring.controller.UserController"/>
</context:component-scan>
@Autowired 自动装配
使用@Autowired注解,可以自动装配bean
示例:
- UserService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.niit.spring.dao.UserDao;
@Service
publicclass UserService {
@Autowired
private UserDao userDao;
publicvoid login() {
userDao.findByName();
}
}
UserDao.java
import org.springframework.stereotype.Repository;
@Repository
publicclass UserDao {
publicvoid findByName() {
System.out.println(“调用了 UserDao 的方法”);
}
}
- ApplicationContext.xml
context:component-scanbase-package=“com.niit.spring”
</context:component-scan>
-
测试
publicstaticvoid main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(“applicationContext.xml”);
UserService us = (UserService)ac.getBean(“userService”);
System.out.println(us);
us.login();
} -
打印
多种类型都匹配的情况
-
新建以下类,一个dao有多个实现类,并在service中注入实现类。
UserService.java
@Service
publicclass UserService {/** * @Autowired优先使用类型匹配的方式装配bean,如果有多个类型都能匹配,会使用变量名和bean的id匹配。 * 也可以使用@Qualifier 注解指定注入的bean */ @Autowired() @Qualifier("userDaoImpl1") private UserDao userDaoImpl1; publicvoid login() { userDaoImpl1.findByName(); }
}
UserDao.java
publicinterface UserDao {
publicvoid findByName();
}
UserDaoImpl1.java
import org.springframework.stereotype.Repository;
@Repository
publicclass UserDaoImpl1 implements UserDao {
@Override
publicvoid findByName() {
System.out.println("UserDaoImpl1 ");
}
}
UserDaoImpl2.java
import org.springframework.stereotype.Repository;
@Repository
publicclass UserDaoImpl2 implements UserDao {
@Override
publicvoid findByName() {
// TODO Auto-generated method stub
System.out.println("UserDaoImpl2");
}
}
-
测试
publicstaticvoid main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(“applicationContext.xml”);
UserService us = (UserService)ac.getBean(“userService”);
System.out.println(us);
us.login();
}
基于Java的配置
无需编写xml
示例
- 新建Appconfig.java类
importorg.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.niit.spring.service.UserService;
/**
- @Configuration用于定义配置类,可以替换xml配置文件。
*/
@Configuration
publicclass AppConfig {
/**
* @bean注册bean对象
* 相当于在xml中的:<bean id="myUserService" class="com.niit.spring.service.UserService"></bean>
* @return
*/
@Bean
public UserService myUserService() {
returnnew UserService();
}
}
UserService.java
@Service
publicclass UserService {
publicvoid login() {
//….
}
}
-
测试
注意:此处需要使用的是AnnotationConfigApplicationContext类。
publicstaticvoid main(String[] args) {
ApplicationContext ac = newAnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService)ac.getBean(“myUserService”);
System.out.println(userService);
} -
结果
配置自动扫描
配置方式也可以使用自动扫描,使用@ComponentScan注解。
- AppConfig.java
/**
- @Configuration用于定义配置类,可以替换xml配置文件。
*@ComponentScan(“com.niit.spring”) 相当于:
*<context:component-scan base-package=“com.niit.spring”>
</context:component-scan>
*/
@Configuration
@ComponentScan(“com.niit.spring”)
//@ComponentScan(basePackages=“com.niit.spring”)//也可以写成这样
publicclass AppConfig {
/**
* @bean注册bean对象
* 相当于在xml中的:<bean id="myUserService" class="com.niit.spring.service.UserService"></bean>
* @return
*/
// @Bean
// @Scope(“prototype”)
// public UserService myUserService() {
// return new UserService();
// }
}
@ComponentScan
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
/**
- @Configuration用于定义配置类,可以替换xml配置文件。
*@ComponentScan(“com.niit.spring”) 相当于:
-
<context:component-scan base-package=“com.niit.spring”>
</context:component-scan>@ComponentScan(basePackages=“com.niit.spring”,
includeFilters=@Filter(Service.class),useDefaultFilters=false)作用相当于:
<context:component-scan base-package=“com.niit.spring” use-default-filters=“false”>
<context:include-filter type=“annotation” expression=“org.springframework.stereotype.Controller”/>
</context:component-scan>@ComponentScan(basePackages=“com.niit.spring”,excludeFilters=@Filter(Service.class))作用相当于:
<context:component-scan base-package=“com.niit.spring” use-default-filters=“false”>
<context:exclude-filter type=“annotation” expression=“org.springframework.stereotype.Service”/>
</context:component-scan>
*/
@Configuration
@ComponentScan(basePackages=“com.niit.spring”,excludeFilters=@Filter(Service.class))
publicclass AppConfig {/**
- @bean注册bean对象
-
相当于在xml中的:<bean id="myUserService" class="com.niit.spring.service.UserService"></bean>
- @return
*/
// @Bean
// @Scope(“prototype”)
// public UserService myUserService() {
// return new UserService();
// }
}
spring容器对bean的管理
bean对象是什么时候被创建的
测试代码
创建一个User类,增加构造器
publicclass User {
public User() {
System.out.println("创建了User对象");
}
}
在applicationContext.xml中配置
<?xml version="1.0" encoding="UTF-8"?><bean class="com.demo.User" id="user">
</bean>
测试类
publicstaticvoid main(String[] args) {
//只加载xml文件创建spring容器实例
ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);
}
运行这个方法,控制台打印:
控制台打印结果显示,默认情况下 User 在 Spring 容器被创建时就会被创建。
修改对象的创建时机
使用lazy-init=true可以改变spring容器创建对象的时机。
单个bean
<?xml version="1.0" encoding="UTF-8"?><bean class="com.demo.User" id="user"lazy-init="true">
</bean>
运行上面的测试代码,会发现什么都不会打印,只有在使用User的时候,才会去创建User对象。
publicstaticvoid main(String[] args) {
//只加载xml文件创建spring容器实例,
ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);
User u = (User) context.getBean(“user”);
u.play();
}
控制台打印:
配置所有的bean都延迟创建
<?xml version="1.0" encoding="UTF-8"?>bean对象的创建模式
bean 对象的创建模式是什么,是单例模式创建 Bean 对象还是每次创建都是新的?
测试代码
User类
publicclass User {
public User() {
System.out.println("创建了User对象");
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?><bean class="com.demo.User" id="user">
</bean>
测试类
创建 2 个 User对象,通过对比,如果为 true,则表明是单例模式;如果为 false,则表明每次都创建新的 User 对象
publicstaticvoid main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);
User u = (User) context.getBean(“user”);
User u1 = (User) context.getBean(“user”);
System.out.println(u == u1);//返回true
}
运行结果:
通过运行结果,我们可以看得出, Spring 容器是通过单例模式创建 Bean 对象的,也就是说,默认情况下,通过调用context.getBean(“user”)方法获得的对象都是同一个 user对象。
修改容器创建对象的模式
使用scope=”prototype”,设置bean的模式为原型模式即可。
<bean class="com.demo.User" id="user"scope="prototype">
</bean>
运行测试代码:
ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);
User u = (User) context.getBean(“user”);
User u1 = (User) context.getBean(“user”);
System.out.println(u == u1);
控制台打印:
此时会发现创建了两个对象。
scope取值
在元素的scope属性里设置bean的作用域,共支持六个范围,其中四个只有在web环境下的applicationContext才可以使用。
Scope的可选范围如下:
request 表示 bean 对象生命周期和 request 生命周期相同
session 同 session
global session 相当于 application
single
prototype
依赖注入
DI(Dependency Injection):
依赖注入,IOC的另一种表达方式。即组件以一些预定好的方式(如setter方法)接受来自如容器的资源注入。相对IOC而言,这种表述更直接。
在springIOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化,只有在容器实例化后,才可以从IOC容器中获取bean实例并使用。
共有两种方式
属性注入(set方法)
构造器注入
注入类型有如下几种: 简单值、集合、 bean 对象。
Ioc 和 DI 的关系?
我们认为 Spring 是具有 IoC 特性的框架。
实现 IoC 是由 Spring 容器来完成的, Spring 容器通过依赖注入 DI 建立起对象(组件、 Bean)之间的关系。
我们可以这样理解: DI 是 IoC 实现的一种手段, Ioc 通过 DI 来实现。
属性注入(set方法)
属性注入即通过setXxx()方法注入Bean的属性值或依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,因此属性注入是实际应用中最常采用的注入方式。
属性注入要求:
Bean提供一个默认的构造函数
为需要注入的属性提供对应的Setter方法。
Spring先调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用Setter方法注入属性值。
示例:
设置简单值
- 创建Book类,并添加set方法
package com.niit.entity;
publicclass Book {
private String name;//书名
privatedoubleprice;//价格
private String publisher;//出版商
//添加get/set方法toString()方法
…
}
- 修改applicationContext.xml
<!-- 设置value的两种方法 -->
<bean id="book" class="com.niit.entity.Book">
<property name="name" value="布瓜的世界"></property>
<property name="price" value="24.5"></property>
<property name="publisher" value="海豚出版社"></property>
</bean>
- 测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.niit.entity.Book;
publicclass TestSpring {
publicstaticvoid main(String[] args) {
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Book book = (Book) classPathXmlApplicationContext.getBean("book");
System.out.println(book);
}
}
结果:打印输出:
引用其他的bean
在配置文件中,可以使用元素或ref属性为bean的属性或构造器参数指定对bean的引用。也可以在属性或构造器里包含bean的声明,这样的bean称为内部bean。
-
新建Student.java
publicclass Student {
private String sname;// 学生姓名
private Book book;// 拥有的书籍//get/set…方法 //toString()方法
}
-
修改applicationContext.xml
<beanid=“book” class=“com.niit.entity.Book”>
<beanid="student"class=“com.niit.entity.Student”>
<propertyname="sname"value=“张三”>
<!—第一种写法:使用ref属性 -->
<propertyname="book"ref=“book”><!—使用ref属性引用id=”book”的bean–>
<!—第二种写法:使用元素 -->
<propertyname=“book”>
<refbean=“book”/>
<!-- 第三种写法:内部bean,它声明在<property>或<constructor-arg>内部,不需要设置id或name属性。只能供内部使用,不能使用在其他任何地方 --> <propertyname="book"> <beanclass="com.niit.entity.Book"> <property name="name" value="布瓜的世界"></property> <property name="price" value="24.5"></property> <property name="publisher" value="海豚出版社"></property> </bean> </property>
-
测试
ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);
Student student = (Student) context.getBean(“student”);
System.out.println(student);
结果打印:
设置级联值
使用上面的Student.java
<beanid=“student” class=“com.niit.entity.Student”>
<propertyname="sname"value=“张三”>
<propertyname="book"ref=“book”><!—注意此处需要先初始化,才能级联赋值,否则会有异常。–>
<property name="book.name"value=“星空”>
构造器注入
构造函数注入是除属性注入之外的另一种常用的注入方式,它保证一些必要的属性在Bean实例化时就得到设置,并且确保了Bean实例在实例化后就可以使用。
使用方式:
- 在类中,不用为属性设置setter方法,但是需要生成该类带参的构造方法。
- 在配置文件中配置该类的bean,并配置构造器,在配置构造器中用到了节点,该节点有四个属性:
· index:索引,指定注入的属性,从0开始;
· name: 构造器参数名
· type是指该属性所对应的类型;
· ref 是指引用的依赖对象;
· value 当注入的不是依赖对象,而是基本数据类型时,就用value;
示例
新建类Book.java
publicclass Book {
private String name;//书名
privatedoubleprice;//价格
private String publisher;//出版商
//添加有参构造器
public Book(String name, doubleprice, String publisher) {
super();
this.name = name;
this.price = price;
this.publisher = publisher;
}}
//重写toString()方法…
}
修改applicationContext.xml
1)第一种写法:默认
<beanid="book"class="com.niit.entity.Book">
<constructor-argvalue="向左走向右走"></constructor-arg>
<constructor-argvalue="12.5"></constructor-arg>
<constructor-argvalue="海豚出版社"></constructor-arg>
</bean>
注:想要给属性设置null值,需使用标签。
如:
2)第二种写法:使用索引index
<beanid="book"class="com.niit.entity.Book">
<constructor-argvalue="向左走向右走"></constructor-arg><!-- 此处index不写,默认为0 -->
<constructor-argvalue="海豚出版社"index="2"></constructor-arg>
<constructor-argvalue="12.5"index="1"></constructor-arg>
</bean>
3)第三种写法:使用类型type匹配
<beanid="book"class="com.niit.entity.Book">
<constructor-argvalue="向左走向右走"></constructor-arg>
<constructor-argvalue="海豚出版社"type="String"></constructor-arg>
<constructor-argvalue="12" type="double"></constructor-arg>
</bean>
4)第四种写法:使用name匹配
<beanid="book"class=“com.niit.entity.Book”>
<constructor-argvalue=“向左走向右走”>
<constructor-argvalue="海豚出版社"name=“publisher”>
<constructor-arg name="num"value=“15”>
注意:使用name匹配,为了保证开箱即用,需开启调试模式。如果不能或不想使用调试编译代码,则需要在构造器上加入@ConstructorProperties注解。
@ConstructorProperties({“name”, “num”,“publisher”})
public Book(String name, intnum, String publisher) {
super();
this.name = name;
this.publisher = publisher;
this.num = num;
}
5)第五种写法:联合使用type和index
示例:
背景:
-
修改Book.java
publicclass Book {
private String name;//书名
privatedoubleprice;//价格
private String publisher;//出版商
//增加图书数量
private int num;//数量//增加包含图书数量的构造器,并将这个包含int类型的构造器,放在包含double构造器之前
public Book(String name, int num, String publisher) {
super();
this.name = name;
this.publisher = publisher;
this.num = num;
}public Book(String name, doubleprice, String publisher) {
super();
this.name = name;
this.price = price;
this.publisher = publisher;
}@Override
public String toString() {
return"Book [name=" + name + “, price=” + price + “, publisher=” + publisher + “, num=” + num + “]”;
}
}
- 修改applicationContext.xml
此时如果修改为以下代码,则会输出不正确的数据(错误示范):
<beanid=“book” class=“com.niit.entity.Book”>
<constructor-argvalue=“向左走向右走”>
<constructor-argvalue=“海豚出版社” index=“2”>
<constructor-argvalue=“12” index=“1”><!—此处的12是价格 -->
原因:构造器的第二个参数设置的值为12,可以是int,也可以是double,此时spring注入参数时,首先加载到第一个构造器,所以会将12作为数量输出,所以就产生了不正确的数据,打印数据如下:
解决方案:同时使用index和type
修改applicationContext.xml,给第二个参数增加type属性限定入参类型。
<beanid=“book” class=“com.niit.entity.Book”>
<constructor-argvalue=“向左走向右走”>
<constructor-argvalue=“海豚出版社” index=“2”>
<constructor-argvalue=“12” index=“1” type=“double”>
- 结果打印(测试代码在下面):
测试代码
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.niit.entity.Book;
publicclass TestSpring {
publicstaticvoid main(String[] args) {
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Book book = (Book) classPathXmlApplicationContext.getBean("book");
System.out.println(book);
}
}