第二章:Spring
第1节:概述
1.1 介绍 heap stack
Spring是一个分层的Java SE/EE full-stack(一站式)轻量级开源框架,以 IoC(Inverse Of Control:控制反转)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。
在java三层架构当中分别提供了相应技术:
表现层(web层) :SpringMVC 框架,servlet
业务层(service层) :Bean管理(IOC容器,在三层都有体现) 声明式事务
持久层(dao层) :JdbcTemplate模板对象以及提供了ORM模块整合其他优秀的持久层技术
spring 框架:
分层一站式框架 轻量 开源
AOP IOC
1.2 发展历程
1997 年, IBM提出了EJB 的思想
1998 年,SUN制定开发标准规范 EJB1.0
1999 年,EJB1.1 发布
2001 年,EJB2.0 发布
2003 年,EJB2.1 发布
2006 年,EJB3.0 发布
Rod Johnson ( Spring 之父)
Expert One-to-One J2EE Design and Development(2002)
阐述了 J2EE 使用EJB 开发设计的优点及解决方案
Expert One-to-One J2EE Development without EJB(2004)
阐述了 J2EE 开发不使用 EJB的解决方式(Spring 雏形)
2017 年 9 月份发布了 Spring 的最新版本 Spring5.0 通用版(GA)
1.3 优势
1. 方便解耦,简化开发:Spring 就是一个大工厂,可以管理所有对象的创建和依赖关系维护,交给Spring管理
2. AOP 编程的支持:可以方便的实现对程序进行权限拦截,日志记录,运行的监控
3. 声明式事务的支持:通过配置方式完成对事务的管理,无需手动编程
4. 方便程序的测试:对Junit支持,可以通过注解方便的对Spring程序进行测试
5. 整合外部优秀技术:Spring内部提供了对各种优秀框架(Hibernate,Mybatis,Quartz等)的直接支持
6. javaEE技术的封装 :Spring对javaEE开发当中复杂难用的API(JavaEmail, RMI等)进行封装,降低了这些API的使用难度。
1.4 体系结构
Spring的核心是容器(IOC): Beans Core Context SpEL表达式
中间层技术:AOP Aspects AOP
web: servler springmvc
data Access: 数据访问层: jdbc ORM 整合外部的优秀框架 Transaction 事务
基于Test测试: spring 整合junit junit4.X
官方网站:
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
第2节:程序的耦合和解耦合
2.1 什么是程序的耦合
话术:
程序的耦合是程序之间的关联性,也就是多个类的联系是否紧密,多个对象之间的关系是否密切。
耦合度高:
(1)不利于扩展
(2)不利于程序的维护。
生活中的案例:
你的房子里面有窗子,那么房子和窗子就有了关联
耦合度是松还是紧就看你的关联是强还是弱,也就是修改的代价,比如你窗子是扣死在墙里的那么你修改窗子就必须修改墙 这就比较紧密了,反应在程序上就是耦合度高,不利于程序的扩展和维护。
但是如果你窗子是按照某种规格的 可以自由拆装的,那么修改的代价就小,耦合度也就低了,反应在程序上就是耦合度低,利于程序的扩展和维护。
我们写程序的目标就是 高内聚 低耦合!
这样修改起来 就不会有太多的联系,不用改一个地方其他的都要修改。
2.2 解决程序耦合的思路
2.2.1 编译不依赖,运行时才依赖
当我们讲解jdbc时,是通过反射来注册驱动的,代码如下:
Class.forName("com.mysql.jdbc.Driver");//使用的驱动类是指定了一个字符串
底层: DriverManager.regist(new com.mysql.jdbc.Driver());
Connection connection = DriverManager.getConnection("","","");
此时的好处式,我们的类中在编译阶段不再需要具体的驱动类,就算删除mysql的驱动jar包,依然可以通过编译。在运行阶段才会依赖驱动包。实际开发当中,我们应该做到编译不依赖,运行时才依赖。
上述代码产生的新问题,mysql驱动类的全限定类名作为一个字符串java类中是写死的,一旦发生改变,还需要修改源码。
使用配置文件结合反射就可以解决上述问题。
2.2.2 使用工厂模式解耦合
在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的 方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。
那么,这个读取配置文件,创建和获取三层对象的类就是工厂。
service 调用dao:
原生: new xxxDaoImpl(); 问题: service实现类当中出现了 new关键字, 出现了dao 层具体的实现类。 不满足java设计原则: 面向接口开发~ 总结: 耦合度高~
工厂模式: XXXFactory.getInstance(); 获得接口的实现类: xxxDao接口接收~ 解决了: new关键字, 业务层的实现类当中, 不在出现dao层的实现类。 总结: 松耦合~
第3节:IOC 机制
3.1 IOC的简介
SpringIOC:IOC 是 Inversion of Control 的缩写,多数书籍翻译成“控制反转”,还有些书籍翻译成为“控制反向”或者“控制倒置”。
就是将对象的创建和维护的权利交给spring 框架。
1996 年,Michael Mattson 在一篇有关探讨面向对象框架的文章中,首先提出了 IOC 这个概念。简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。
IOC 理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦 如下图
大家看到了吧,由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了, 全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合 在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来。
我们再来做个试验:把上图中间的IOC容器拿掉,然后再来看看这套系统:
我们现在看到的画面,就是我们要实现整个系统所需要完成的全部内容。这时候,A、B、C、D这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话, 当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。所以,如果真能实现IOC容器,对于系统开发而言,这将是 一件多么美好的事情,参与开发的每一成员只要实现自己的类就可以了,跟别人没有任何关系!
总结:
IOC容器就是创建对象, 并且维护对象和对象之间的关联关系。
3.2 IOC作用
IOC本质上就是一个大工厂,大容器。主要作用就是创建和管理对象的依赖关系,削减计算机程序的耦合(解除我们代码中的依赖关系),提高程序的可扩展性和可维护性。
3.3 IOC入门
3.3.1 构建工程添加依赖
<properties>
<spring.version>5.2.5.RELEASE</spring.version>
</properties>
<!--导入spring的context坐标,context依赖core、beans、expression aop-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
3.3.2 创建持久层接口和实现类
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("userDao save method running...... ");
}
}
3.3.3 创建业务层接口和实现类
public interface UserService {
public void saveService();
}
public class UserServiceImpl implements UserService {
@Override
public void saveService() {
System.out.println("userSerivce save method running......");
}
}
3.3.4 创建IOC配置文件
xml文件名称: applicationContext.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
3.3.5 配置文件管理对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置userDaoImpl-->
<bean id="userDao" class="com.ujiuye.dao.impl.UserDaoImpl"></bean>
<!--配置userServiceImpl-->
<bean id="userService" class="com.ujiuye.service.UserServiceImpl"></bean>
</beans>
3.3.6 测试
@Test
public void test1(){
//1:获得spring IOC容器对象:
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//2:从容器当中根据id获得UserDaoImpl 对象,执行userDao对象的save方法
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
//3:从容器当中根据id获得UserServiceImpl 对象,执行userService对象的saveService方法
UserService userService = (UserService)applicationContext.getBean("userService");
userService.saveService();
}
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zu3nHWrz-1666881307897)(.\images\运行结果1.png)]
第4节:基于XML的IOC
4.1 IOC配置文件详解
bean标签: 用于配置对象交给Spring 来创建。
默认情况下他会调用类中无参数的构造器,如果没有无参数构造器则不能成功创建
基本属性:
id : Bean实例对象在Spring容器当中的唯一标识
class : Bean的全限定类名
name : 了解,给对象命名操作
4.2 源码解析
4.2.1 IOC容器解析(面试题目)
IOC思想基于IOC容器完成,IOC容器底层就是对象工厂,Spring 中工厂的类结构图如下:
1. BeanFactory :该接口是顶层接口, IOC容器的基本实现,是Spring内部使用的接口,不提供开发人员使用,加载配置文件时,不会创建对象,在获得(使用)对象时才采取创建对象。对象的创建时机,getBean()创建【稍后演示】
2. HierarchicalBeanFactory:这个工厂接口非常简单,实现了Bean工厂的分层。 工厂接口也是继承自BeanFacotory,也是一个二级接口,相对于父接口,它只扩展了一个重要的功能——工厂分层
3. AutowireCapableBeanFactory:该接口有自动装配能力,需要注意的是,ApplicationContext接口并没有实现此接口,因为应用代码很少用到此功能,如果确实需要的话,可以调用ApplicationContext的getAutowireCapableBeanFactory方法,来获取此接口的实例。
4. ListableBeanFactory:获取bean时,Spring 鼓励使用这个接口定义的api,如查看Bean的个数、获取某一类型Bean的配置名、查看容器中是否包括某一Bean等方法。
5. ApplicationContext: BeanFactory接口的子接口,提供更多强大的功能,一般由开发人员使用.接口提供了bean基础性操作同时,扩展了国际化等功能。ApplicationContext接口在加载配置文件时候就会配置文件当中的对象进行创建,存放在IOC容器当中
6. AnnotationConfigApplicationContext:
当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
7. ClassPathXmlApplicationContext:
它是从类的根路径下加载配置文件 推荐使用这种
8. FileSystemXmlApplicationContext:
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
重点掌握: BeanFactory ApplicationContext
面试题目: BeanFactory & ApplicationContext 联系和区别:
BeanFactory : 顶层接口, 接口当中实现了基础性的功能。 提供给框架设计者使用。
加载配置文件的时候, 对象不创建。 getBean();才会创建对象。
ApplicationContext :是BeanFactory 接口的子接口。 提供了基础性功能之外, 功能进行了扩展,开发者使用。
加载配置文件的时候, 对象就创建成功, 并且存放在IOC 容器当中。
ClassPathXmlApplicationContext: 从类路径下获得资源文件。
AnnotationConfigApplicationContext: 基于主机模式使用的实现类。
第5节:手动实现自己的IOC容器
5.1 分析IOC 实现思路
思路:
1、创建工厂对象,加载Spring核心配置文件
2、使用xml解析技术,获得bean标签当中id属性以及class属性对应的值
3、底层使用反射技术,创建对象
4、准备临时容器,存放创建的对象
5、提供getBean方法,对外提供对象
6、测试自定义的工厂对象
5.2 设计接口、类和配置文件
//设定UserDao接口
public interface UserDao {
public void save();
}
//设定UserDao接口实现类
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("userDao save method running...... ");
}
}
5.3 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userDao" class="com.offcn.dao.impl.UserDaoImpl"></bean>
<bean id="userService" class="com.offcn.service.impl.UserServiceImpl"></bean>
</beans>
5.4 解析配置文件
dom4J, jdom sax jaxp 解析器
<!--引入dom4J-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
/**
* 创建自己的工厂类
*/
public class MyBeanFactory {
//创建一个map集合,模拟IOC容器
private static Map<String,Object> map = new HashMap<>();
static{
try {
//使用dom4J 解析xml文件:
//第一步:获得一个解析器:
SAXReader reader = new SAXReader();
//第二: 读取外部的配置文件:
String path = "src/main/resources/myApplicationContext.xml";
//第三: 读取了整个文档对象
Document document = reader.read(path);
//第四: 获得根节点:
Element rootElement = document.getRootElement();//beans
//第五: 获得根节点下的所有的bean 标签对应的节点:
List<Element> bean = rootElement.elements("bean");// bean
for (Element element : bean) {
//获得id属性对应的值:
String id1 = element.attributeValue("id");
//获得class属性对应的值:【全限定类名】
String aClass = element.attributeValue("class");//获得class对应的值: 全限定类名。
//通过反射创建对象:
Class clz = Class.forName(aClass);
Object object = clz.newInstance();
//存容器 id做key,创建出来的对象value
map.put(id1,object);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据id从容器当中获得对象
* @param id id的名称
* @return 返回Object类型对象
*/
public static Object getBean(String id){
Object o = map.get(id);
return o;
}
}
总结: IOC容器自定义时候;
xml解析技术:
反射技术
工厂模式
5.5 测试
@Test
public void testMyFactory(){
//1:创建工厂对象
MyBeanFactory factory =new MyBeanFactory();
//2:从容器当中根据id获得对象
UserDao userDao = (UserDao) factory.getBean("userDao");
System.out.println(userDao);
userDao.save();
}
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xHx59dsX-1666881307900)(./images/运行结果2.png)]
第6节:管理bean细节
6.1 bean实例化介绍
bean 对象创建~
6.2 bean实例化方式【面试问题】
6.2.1 构造方法的方式
它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败
(1)创建User类
public class User implements Serializable {
public User(){
System.out.println("user created...");
}
}
(2)配置容器管理对象
<!--配置user对象-->
<bean id="user" class="com.ujiuye.pojo.User"></bean>
(3)测试实例化对象
@Test
public void testUser(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user);
}
6.2.2 静态工厂方式
(1)创建静态工厂
public class ItemFactory {
//静态方法返回实例bean
public static User createUser(){
System.out.println("static method running create bean ......");
return new User();
}
}
(2)配置容器管理对象
<!--静态工厂实例化对象:
工厂方法的返回值存放在IOC容器当中
-->
<bean id="user" class="com.ujiuye.factory.ItemFactory" factory-method="createUser"></bean>
(3)测试实例化对象
@Test
public void testItemFactory(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user);
}
6.2.3 实例工厂方式
(1)创建实例工厂
public class NewItemFactory {
//工厂的非静态方法返回bean实例
public User createUser(){
System.out.println("Dynamic method running create bean ......");
return new User();
}
}
(2)配置容器管理对象
<!--实例工厂:
步骤一; 创建对象
步骤二: 通过对象调用方法,方法的返回值存在IOC容器当中。
-->
<bean id="itemFactory" class="com.ujiuye.factory.NewItemFactory"></bean>
<bean id="user" factory-bean="itemFactory" factory-method="createUser"></bean>
(3)测试实例化对象
@Test
public void testNewItemFactory(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user);
}
6.3 bean作用域【面试问题】
6.3.1 bean作用域介绍
所谓Bean的作用域其实就是指Spring给我们创建出的对象的存活范围,在配置文件中通过bean的scope属性指定
<bean id="" class="" scope="">
scope:指对象的作用范围,取值如下:
取值范围 | 说明 |
---|---|
singleton | 默认值,单例的 |
prototype | 多例的 |
request | WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中 |
session | WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中 |
global session | WEB 项目中,应用在 Portlet 环境,如果没有 Portlet 环境那么globalSession 相当于 session |
6.3.2 bean作用域的解析
(1)scope取值为singleton
Bean的实例化个数:1个
Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
(2)scope取值为prototype
Bean的实例化个数:多个
Bean的实例化时机:当调用getBean()方法时实例化Bean
注意: 多例对象,不会随容器而创建, 不会随容器销毁而销毁。
在内存当中, 由垃圾回收器定期回收~
(3)Scope取值为其他值
scope指定为其他值,需要在特定的环境下使用, 只需要作为一个了解知识,面试能够回答出来即可
6.4 bean的生命周期
6.4.1 bean生命周期介绍
在这里所谓的Bean的生命周期其实指的是Bean创建到销毁的这么一段时间。
在Spring中可以通过配置的形式,指定bean在创建后和销毁前要调用的方法。
属性:
init-method:指定bean在创建后调用的方法
destroy-method:对象在销毁前调用的方法
<bean id="xxx" class="xxx" init-method="" destroy-method=""></bean>
6.4.2 单例对象的生命周期
(1)添加方法init和destory
public class UserServiceImpl implements UserService {
public void init(){
System.out.println("init method running...");
}
@Override
public void saveService() {
System.out.println("userSerivce save method running......");
}
public void destroy(){
System.out.println("destroy method running...");
}
}
(2)配置文件中配置UserService
<!--配置userServiceImpl-->
<bean id="userService" class="com.ujiuye.service.UserServiceImpl" init-method="init" destroy-method="destroy">
</bean>
(3)测试单例对象生命周期
@Test
public void test1(){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.saveService();
//关闭工厂:
applicationContext.close();
}
单例对象总结:
对象创建:当应用加载,创建容器时,对象就被创建了
对象运行:只要容器在,对象一直活着
对象销毁:当应用卸载,销毁容器时,对象就被销毁了
6.4.3 多例对象的生命周周期
(1)配置文件scope属性
<!--配置userServiceImpl-->
<bean id="userService" class="com.ujiuye.service.UserServiceImpl" init-method="init" destroy-method="destroy" scope="prototype"></bean>
(2)测试多例对象生命周期
@Test
public void test1(){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.saveService();
//关闭工厂:
applicationContext.close();
}
多例对象总结:
对象创建:当使用对象时(getBean),创建新的对象实例
对象运行:只要对象在使用中,就一直活着
对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了, 对destroy-method属性针对多例不生效。
第7节:依赖注入
7.1 介绍
依赖注入(Dependency Injection):简称DI,它是 Spring 框架核心 IOC 的具体实现。
在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。
IOC 解耦只是降低他们的依赖关系,但不会消除。
例如:业务层仍会调用持久层的方法。
那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取
简单理解: 依赖注入就是spring IOC 容器在创建对象的时候, 给属性赋值。
7.2 依赖注入方式
7.2.1 构造函数注入
(1)创建实体类
顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置
的方式,让 Spring 框架来为我们注入。具体代码如下
public class Account {
private String name;
private Integer age;
private Date birthday;
public Account(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
}
(2)配置文件管理类
<!--使用构造函数的方式:给account中的属性赋值
要求:
类中需要提供一个对应参数列表的构造器函数
涉及的标签:
constructor-arg:
属性:
name: 执行参数在构造器中的名称
value:它能赋的值是基本数据类型和 String 类型
ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
-->
<bean id="now" class="java.util.Date"></bean>
<bean id="account" class="com.ujiuye.pojo.Account">
<constructor-arg name="name" value="王达"></constructor-arg>
<constructor-arg name="age" value="20"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
(3)构造函数注入测试
@Test
public void testDI(){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
Account account = (Account) applicationContext.getBean("account");
System.out.println("name:"+account.getName()+" age:"+account.getAge()+" birthday:"+account.getBirthday());
//打印结果: name:王达 age:20 birthday:Thu Feb 04 13:53:45 CST 2021
}
7.2.2 setter注入
(1)修改类添加setter方法
顾名思义,就是在类中提供需要注入成员的 set 方法。具体代码如下:
public class Account {
private String name;
private Integer age;
private Date birthday;
public Account() {
}
public Account(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
(2)注入依赖数据
<!--使用set方法的方式给属性赋值
涉及的标签:
property
属性:
name:找的是类中set方法后面的部分
ref: 给属性赋值是其他bean类型的
value:给属性赋值是基本数据类型和 string 类型的
实际开发当中, 此种方式用的比较多,推荐使用
-->
<bean id="now" class="java.util.Date"></bean>
<bean id="account" class="com.ujiuye.pojo.Account">
<property name="name" value="张三丰"></property>
<property name="age" value="31"></property>
<property name="birthday" ref="now"></property>
</bean>
(3)setter注入测试方法
@Test
public void testDI(){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
Account account = (Account) applicationContext.getBean("account");
System.out.println("name:"+account.getName()+" age:"+account.getAge()+" birthday:"+account.getBirthday());
//测试结果: name:张三丰 age:31 birthday:Thu Feb 04 14:05:19 CST 2021
}
7.2.3 P名称空间注入
语法: p:属性名称=“”
在xml当中引入p名称空间
xmlns:p="http://www.springframework.org/schema/p"
语法:
<bean id="account" class="com.offcn.pojo.Account" p:name="唐晓飞" p:age="21" p:birthday-ref="birthday"></bean>
7.2.4 SPEL 表达式注入
<!--SPEL注入: spring el expression
(1) 底层是调用了set方法
(2) #{} spring EL 语法
(3) 不管是普通属性或者是对象属性, 都使用value 赋值。
(4)功能最强大 , 属性赋值的时候,可以调用对象的属性, 可以调用对象的方法。
-->
<bean id="account" class="com.offcn.pojo.Account">
<property name="name" value="#{'admin'}"></property>
<property name="age" value="#{account.calcullatorAge()}"></property>
<property name="birthday" value="#{birthday}"></property>
</bean>
7.3 注入集合数据
7.3.1 添加集合属性
顾名思义,就是给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。
我们这里介绍注入数组,List,Set,Map,Properties。具体代码如下:
public class Account {
//注入数组,List集合,Set集合,Map集合,Properties集合属性
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
public Account() {
}
public String[] getMyStrs() {
return myStrs;
}
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public List<String> getMyList() {
return myList;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public Set<String> getMySet() {
return mySet;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public Map<String, String> getMyMap() {
return myMap;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public Properties getMyProps() {
return myProps;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
}
7.3.2 注入依赖集合数据
<!--注入集合类型数据:
涉及到标签:
List结构: array list set
Map结构: map entry props prop
-->
<bean id="account" class="com.ujiuye.pojo.Account">
<!--注意:在注入集合数据时,只要是结构相同,标签可以互换-->
<!--注入数组数据-->
<property name="myStrs">
<array>
<value>array-AAA</value>
<value>array-BBB</value>
<value>array-CCC</value>
</array>
</property>
<!--注入List集合数据-->
<property name="myList">
<list>
<value>list-AAA</value>
<value>list-BBB</value>
<value>list-CCC</value>
</list>
</property>
<!--注入Set集合数据-->
<property name="mySet">
<list>
<value>set-AAA</value>
<value>set-BBB</value>
<value>set-CCC</value>
</list>
</property>
<!--注入Map集合-->
<property name="myMap">
<map>
<entry key="map-a" value="AAA"></entry>
<entry key="map-b">
<value>BBB</value>
</entry>
</map>
</property>
<!--注入Properties集合-->
<property name="myProps">
<props>
<prop key="pro-a">AAA</prop>
<prop key="pro-b">BBB</prop>
</props>
</property>
</bean>
7.3.3 集合注入测试方法
@Test
public void testDI(){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
Account account = (Account) applicationContext.getBean("account");
System.out.println("array:"+ Arrays.toString(account.getMyStrs()));
System.out.println("list:"+account.getMyList());
System.out.println("set:"+account.getMySet());
System.out.println("map:"+account.getMyMap());
System.out.println("props:"+account.getMyProps());
/*
测试结果:
array:[array-AAA, array-BBB, array-CCC]
list:[list-AAA, list-BBB, list-CCC]
set:[set-AAA, set-BBB, set-CCC]
map:{map-a=AAA, map-b=BBB}
props:{pro-b=BBB, pro-a=AAA}
*/
}