Spring01

1. Spring概述

1.1. Spring是什么

Spring是一个轻量级的框架,那什么是框架了?

框架是可以重复使用的一些或一整套代码,通常与具体业务无关,也可以认为是软件的半成品。

使用框架的好处:简化项目的开发,提高开发效率。

什么又是“一站式”框架呢?

JavaEE开发规范规定我们的程序应该要分为三层:WEB层、业务层、持久层。每一层的含的含义如下:

l WEB层(页面数据显示、页面跳转调度)-jsp/servlet

业务层(业务处理和功能逻辑、事务控制)-serivice

持久层(数据存取和封装、和数据库打交道)-dao

JavaEE三层架构中每一层都有对应的解决方案:WEB层可以采用Struts2;持久层可以采用Hibernate;而业务层是需要处理事务的,利用Spring中的AOP可以很好的管理事务。每一层所对应的框架如下图所示:


那什么是“一站式”呢?“一站式”指的是Spring框架提供了JavaEE三层架构中每一层的解决方案。通过前面的分析我们知道,WEB层可以用Struts2,持久层可以用Hibernate。现在WEB层和持久层也可以采用其他技术,WEB层可以用Spring中的MVC模块,持久层可以用Spring中的JdbcTemplate技术。这样一来的话,JavaEE三层中的架构中的每一层都可以采用Spring来解决,所以我们称Spring是“一站式”框架,意思是采用Spring这一个框架就足够了,Spring给我们提供“一条龙”服务。JavaEE三层每一层都采用Spring来解决的示意图如下:


总结一句话:Spring是一个分层的“一站式”轻量级开源框架。

1.2. Spring体系架构


1.3. Spring的优势

方便解耦,简化开发

通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

AOP编程的支持

通过SpringAOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。

声明式事务的支持

可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。

方便程序的测试

可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。

方便集成各种优秀框架

Spring可以降低各种框架的使用难度,提供了对各种优秀框架(StrutsHibernateHessianQuartz等)的直接支持。

降低JavaEE API的使用难度

SpringJavaEE API(如JDBCJavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低。

2. Spring IOC快速入门

2.1. 什么是IOC

IOC,它是Inverse of Control的缩写,中文含义是控制反转,表示将对象的创建权力反转给Spring框架!!

IOC解决的问题:使用IOC可以解决的程序耦合性高的问题!!

那么什么是程序的耦合呢?

2.2. 什么是程序的耦合

我们在开发中,会写很多的类,而有些类之间不可避免的产生依赖关系,这种依赖关系称之为耦合。有些依赖关系是必须的,有些依赖关系可以通过优化代码来解除的。

请看下面的示例代码:

首先,创建maven工程:spring4_day01_myioc


n 创建UserDao接口


 

public interface UserDao {

 

public void save();

}

创建UserDao接口的实现类UserDaoImpl

 

 

public class UserDaoImpl implements UserDao {

 

@Override

public void save() {

System.out.println("持久层:用户保存...");

}

 

}

创建UserDao接口的第二个实现类UserDaoImpl2

 

public class UserDaoImpl2 implements UserDao {

 

@Override

public void save() {

System.out.println("持久层:用户保存22222.....");

}

 

}

创建UserService接口

 

 

 

public interface UserService {

 

public void saveUser();

}

创建UserService接口的实现类UserServiceImpl

 

public class UserServiceImpl implements UserService {

private UserDao userDao = new UserDaoImpl();

@Override

public void saveUser() {

userDao.save();

}

 

}

创建单元测试类TestIOC,在其中创建test1单元测试方法,测试UserServiceImpl能否调用UserDaoImpl

 

public class TestIOC {

 

@Test

public void test1(){

UserService userService = new UserServiceImpl();

userService.saveUser();

}

}

运行test1方法,测试结果如下:



以上程序,UserServiceImplUserDaoImpl就耦合了,因为在UserServiceImpl中直接实例化了UserDaoImplUserServiceImplUserDaoImpl联系太过紧密了。耦合性过高的弊端就在于,当在UserServiceImpl中需要更换为UserDaoImpl2时,就需要改源码了,违背了软件开发领域的“开闭”原则。

 

那怎么样才能让UserServiceImpl需要更换UserDao的实现时,不用修改UserServiceImpl的源码?也就是让UserServiceImplDAO解耦。首先,可以采用工厂的方式来解耦。下面,我们来看下采用工厂的方式该如何解耦?

2.3. 创建工厂类解决耦合性的问题

创建工厂类BeanFactory


/**

 * 专门用来生产bean的工厂类

 */

public class BeanFactory {

/**

 * 获取bean对象的工厂方法

 * @return

 */

public static UserDao getBean(){

return new UserDaoImpl();

}

}

修改UserServiceImpl类,不用再手动实例化DAO了,而是通过工厂类的方式来获取DAO

public class UserServiceImpl implements UserService {

//手动实例DAO,Service严重耦合DAO

//private UserDao userDao = new UserDaoImpl();

//通过工厂的方式来获取DAO对象

private UserDao userDao = BeanFactory.getBean();

 

@Override

public void saveUser() {

userDao.save();

}

 

}

2.4. 创建配置文件彻底解决耦合性的问题

src/main/resources下创建配置文件beans.xml


修改工厂类BeanFactory,从配置文件读取bean信息,读取配置文件时需要用到dom4j,故先引入dom4j的依赖,坐标如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>cn.itcast</groupId>

<artifactId>spring_day01_myioc</artifactId>

<version>0.0.1-SNAPSHOT</version>

<dependencies>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.12</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>dom4j</groupId>

<artifactId>dom4j</artifactId>

<version>1.6.1</version>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-compiler-plugin</artifactId>

<version>3.5.1</version>

<configuration>

<source>1.7</source>

<target>1.7</target>

</configuration>

</plugin>

</plugins>

</build>

</project>

/**

 * 专门用来生产bean的工厂类

 *

 * @author kevin

 */

public class BeanFactory {

 

/*

 * public static UserDao getBean(){ return new UserDaoImpl(); }

 */

 

// 从xml文件中解析bean,通过反射得到的对象存放到map中

private static Map<String, Object> map = new HashMap<String, Object>();

/**

 * 解析xml文件

 */

static {

SAXReader saxReader = new SAXReader();

try {

Document document = saxReader.read(BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml"));

Element root = document.getRootElement();

String id = root.attributeValue("id");

// 类的全路径名

String clazz = root.attributeValue("class");

// 通过反射生成对象

Object obj = Class.forName(clazz).newInstance();

map.put(id, obj);

} catch (Exception e) {

e.printStackTrace();

}

}

 

/**

 * 获取bean对象的工厂方法

 *

 * @return

 */

public static Object getBean(String id) {

return map.get(id);

}

}

修改UserServiceImpl类,改为通过工厂类获取UserDao对象

public class UserServiceImpl implements UserService {

//手动实例DAO,Service严重耦合DAO

//private UserDao userDao = new UserDaoImpl();

//通过工厂的方式来获取DAO对象

private UserDao userDao = (UserDao) BeanFactory.getBean("userDao");

 

@Override

public void saveUser() {

userDao.save();

}

 

}

此时,我们的程序已经真正解耦了,当UserServiceImpl需要更换DAO时,只需要修改beans.xml文件即可,不需要改源代码了。


2.5. Spring开发包

n 采用4.2.4这个版本


spring-framework.jar包解压,开发包目录结构如下:


2.6. Spring IOC入门

2.6.1. 创建工程并引入依赖

n 引入spring ioc依赖的jar包,坐标如下:

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>4.2.4.RELEASE</version>

</dependency>

n Spring运行还需要日志环境,这里我们引入log4jjar包,坐标如下:

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.12</version>

</dependency>

n 后面还需要做单元测试,引入junit的依赖,坐标如下:

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.12</version>

<scope>test</scope>

</dependency>

n Spring框架在运行时需要有日志环境的支持,前面我们已经导入了log4jjar包,还需要引入log4j的配置文件log4j.properties:


2.6.2. 创建一个接口和实现类


public interface UserDao {

 

public void save();

}

创建UserDao接口的实现类UserDaoImpl


public class UserDaoImpl implements UserDao {

 

@Override

public void save() {

System.out.println("持久层:用户保存...");

}

 

}

2.6.3. 创建Spring的核心配置文件

src/main/resources下新建Spring核心配置文件applicationContext.xml


applicationContext.xml中引入约束,约束的内容可以从spring的官方文档中拷贝


引入约束后的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>

如何配置XML自动提示?

如果电脑可以联网,自动从网上下载 DTD,在编写xml文件时就有了提示。

如果电脑没有联网,在本地配置DTD文件位置,提供本地提示。

n 配置XML自动提示步骤:

第一步:从applicationContext.xml中复制dtd网址:


第二步:选择window-Preferences


选择Xml Catalog


点击Add




2.6.4. 配置UserDaoImpl

applicationContext.xml配置UserDaoImpl

<?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">

        <bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl"></bean>

</beans>

id属性指定bean的唯一标识;class属性指定bean的全路径名。

2.6.5. 编写测试类

在src/test/java创建单元测试类TestIOC


public class TestIOC {

 

@Test

public void test1(){

//创建Spring工厂(创建IOC容器)

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

UserDao userDao  = (UserDao) ac.getBean("userDao");

userDao.save();

}

 

 

}

测试发现:我们可以从spring容器中获取对象。


3. Spring中的工厂

spring中提供了两个工厂接口:

1、ApplicationContext

2、BeanFactory

3.1. ApplicationContext接口

使用该接口可以获取到具体的Bean对象

n 该接口下有两个具体的实现类

* ClassPathXmlApplicationContext            -- 加载类路径下的Spring配置文件
 * FileSystemXmlApplicationContext            -- 加载本地磁盘下的Spring配置文件

下面演示FileSystemXmlApplicationContext的用法:

src下的applicationContext.xml拷贝到你电脑的某个目录,例如:c:/spring,可以通过FileSystemXmlApplicationContext加载本地磁盘下的spring配置文件

public class TestIOC {

 

@Test

public void test1(){

//创建Spring工厂(创建IOC容器)

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

UserDao userDao  = (UserDao) ac.getBean("userDao");

userDao.save();

}

@Test

public void test2(){

//创建Spring工厂(创建IOC容器)

ApplicationContext ac = new FileSystemXmlApplicationContext("C:/spring/applicationContext.xml");

UserDao userDao  = (UserDao) ac.getBean("userDao");

userDao.save();

}

}

3.2. BeanFactory工厂

BeanFactorySpring框架早期的创建Bean对象的工厂接口。在TestIOC中创建test3测试方法:

/**

 * 早期版本的spring工厂:BeanFactory

 */

@Test

public void test3(){

BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

UserDao userDao = (UserDao) factory.getBean("userDao");

userDao.save();

}

n BeanFactoryApplicationContext的区别
            * BeanFactory                -- BeanFactory采取延迟加载,第一次getBean时才会初始化Bean
            * ApplicationContext        -- 在加载applicationContext.xml时候就会创建具体的Bean对象的实例

修改UserDaoImpl,增加一个无参构造方法,运行test1test3两个单元测试方法,验证ApplicationContextBeanFactory这两个工厂到底什么时候创建bean对象??

public class UserDaoImpl implements UserDao {

public UserDaoImpl() {

System.out.println("调用了无参构造方法...");

}

 

public void save(){

System.out.println("持久层:用户保存...");

}

 

}

修改test1单元测试方法:

/**

 * 创建ioc容器时就已经把对象创建好了

 */

@Test

public void test1(){

//创建Spring工厂(创建IOC容器)

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

System.out.println("===============");

UserDao userDao  = (UserDao) ac.getBean("userDao");

userDao.save();

}

 

运行test1方法,发现:ApplicationContext是在创建ioc容器时就已经把对象创建好了


修改test3单元测试方法:

/**

 * 创建ioc容器时并没有创建对象,而是在第一次getBean时再创建对象

 */

@Test

public void test3(){

//创建Spring工厂(创建IOC容器)

BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

System.out.println("===============");

UserDao userDao  = (UserDao) factory.getBean("userDao");

userDao.save();

}

运行test3方法,发现:BeanFactory创建ioc容器时并没有创建对象,而是在第一次getBean时再创建对象


4. Spring配置文件

4.1. id属性

id属性是bean的唯一标识

4.2. class属性

bean的全路径名

 <bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl"/>

4.3. scope属性

scope属性代表Bean的作用范围

singleton:单例(默认值)

prototype:多例,在Spring框架整合Struts2框架的时候,Action类也需要交给Spring做管理,配置把Action类配置成多例!!

request:应用在web应用中,将创建的对象存入到request域中。

session:应用在web应用中,将创建的对象存入到session域中

globalsession:应用在porlet环境下使用。将创建的对象存入到全局的session中。

示例:<bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl" scope="prototype"/>

修改applicationContext.xml,把UserDaoImpl的作用域改为prototype

<?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">

      

     <bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl" scope="prototype"></bean>

    

</beans>

修改test1单元测试方法:

@Test

public void test1(){

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

System.out.println("===============");

UserDao userDao  = (UserDao) ac.getBean("userDao");

UserDao userDao1 = (UserDao) ac.getBean("userDao");

System.out.println(userDao==userDao1);

userDao.save();

}

测试发现:scopeprototype时,每次获取bean,都会重新实例化


4.4. init-method属性

bean被载入到容器的时候调用init-method属性指定的方法

修改UserDaoImpl,在其中提供init方法

public class UserDaoImpl implements UserDao {

public UserDaoImpl() {

System.out.println("调用了无参构造方法...");

}

 

public void init(){

System.out.println("调用了init方法...");

}

public void save(){

System.out.println("持久层:用户保存...");

}

 

}

n 运行test1单元测试方法,测试结果:




4.5. destory-method属性

bean从容器中删除的时候调用destroy-method属性指定的方法

想查看destroy-method的效果,有如下条件:

scope= singleton有效

web容器中会自动调用,但是main函数或测试用例需要手动调用(需要使用ClassPathXmlApplicationContextclose()方法)

修改UserDaoImpl,在其中提供destroy方法

public class UserDaoImpl implements UserDao {

public UserDaoImpl() {

System.out.println("调用了无参构造方法...");

}

 

public void init(){

System.out.println("调用了init方法...");

}

public void save(){

System.out.println("持久层:用户保存...");

}

 

public void destroy(){

System.out.println("调用了销毁方法...");

}

}

applicationContext.xml中为UserDaoImpl指定销毁方法

<?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">

      

     <bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>

    

</beans>

修改test1单元测试方法,显示关闭ioc容器:

@Test

public void test1(){

//创建Spring工厂(创建IOC容器)

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

System.out.println("==============");

UserDao userDao1  = (UserDao) ac.getBean("userDao");

UserDao userDao2  = (UserDao) ac.getBean("userDao");

System.out.println(userDao1 == userDao2);

//显示关闭ioc+bean一定要是单例的

((ClassPathXmlApplicationContext)ac).close();

}

测试结果如下:


5. Spring生成bean的三种方式

5.1. 无参构造方法

默认调用无参构造方法实例化bean。在此之前,都是调用无参构造来实例化的。

5.2. 静态工厂实例化方式

通过调用工厂类的静态方法来生成bean

编写DeptDao接口


package cn.itcast.dao;

 

public interface DeptDao {

 

public void save();

}

编写DeptDaoImpl实现类


public class DeptDaoImpl implements DeptDao{

 

@Override

public void save() {

System.out.println("持久层:部门保存...");

}

 

}

n 编写工厂类,在其中创建静态工厂方法


public class Factory {

 

/**

 * 静态工厂方法

 */

public static DeptDao create(){

System.out.println("调用了静态工厂方法");

return new DeptDaoImpl();

}

}

编写applicationContext.xml配置文件,采用静态工厂方式配置DeptDaoImpl

<?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">

      

     <bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>

     <bean id="deptDao" class="cn.itcast.factory.Factory" factory-method="create"></bean> 

</beans>

在配置DeptDaoImpl这个bean,class属性写的不是DeptDaoImpl的全路径名,而是工厂类的全路径名;

factory-method:指定工厂类中静态方法的名字

在TestIOC类中编写测试方法test4

@Test

public void test4(){

//创建Spring工厂(创建IOC容器)

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

DeptDao deptDao = (DeptDao) ac.getBean("deptDao");

deptDao.save();

}

测试结果如下:


5.3. 实例工厂实例化方式

n 修改Factory工厂类,创建实例工厂方法:

public class Factory {

 

/**

 * 静态工厂方法

 */

/*public static DeptDao create(){

System.out.println("调用了静态工厂方法");

return new DeptDaoImpl();

}*/

/**

 * 实例工厂方法

 * @return

 */

public  DeptDao create(){

System.out.println("调用了实例工厂方法");

return new DeptDaoImpl();

}

}

factory-bean:指定工厂beanid;

Factory-method:指定工厂bean的实例工厂方法的名字

运行test4测试方法,测试结果如下:


6. 依赖注入

6.1. 什么是依赖注入

IOCDI的概念:
* IOC        -- Inverse of Control,控制反转,将对象的创建权反转给Spring!!

* DI        -- Dependency Injection,依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!!

如果UserServiceImpl的实现类中有一个属性,那么使用Spring框架的IOC功能时,可以通过依赖注入把该属性的值传入进来!!

6.2. 构造方法注入

什么是构造方法注入?构造方法注入就是利用bean的构造方法完成对bean中属性的赋值。

创建Car实体类,提供有参构造方法


package cn.itcast.domain;

 

public class Car implements Serializable{

private static final long serialVersionUID = 1L;

private String name;

private Double price;

public Car(String name, Double price) {

this.name = name;

this.price = price;

}

 

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

 

public Double getPrice() {

return price;

}

 

public void setPrice(Double price) {

this.price = price;

}

 

@Override

public String toString() {

return "Car [name=" + name + ", price=" + price + "]";

}

}

创建applicationContext2.xml,applicationContext2.xml配置Car这个bean


<?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">

<!-- 构造方法注入 -->

<bean id="car" class="cn.itcast.domain.Car">

<constructor-arg name="name" value="奥迪A6"></constructor-arg>

<constructor-arg name="price" value="57.3"></constructor-arg>

</bean>

</beans>

n 创建单元测试类TestDI,在其中创建单元测试方法test1测试,注意此处创建IOC容器时,应该加载applicationContext2.xml


public class TestDI {

 

@Test

public void test1(){

//创建Spring工厂(创建IOC容器)

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext2.xml");

Car car = (Car) ac.getBean("car");

System.out.println(car);

}

 

}

n 运行结果:


6.3. set方法注入

什么是set方法注入?set方法注入就是利用bean中属性的set方法对属性赋值。

创建People实体类,提供属性的set方法,不需要提供有参构造方法。


public class People implements Serializable {

 

private static final long serialVersionUID = 1L;

private String name;//要提供属性所对应的set方法

private String address;

private Car car;//对象属性

public void setName(String name) {

this.name = name;

}

public void setAddress(String address) {

this.address = address;

}

public void setCar(Car car) {

this.car = car;

}

 

@Override

public String toString() {

return "People [name=" + name + ", address=" + address + ", car=" + car + "]";

}

 

}

applicationContext.xml2中配置People实体类,普通属性用value指定值,对象属性用ref指定需要注入的beanid.

<?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">

<!-- 构造方法注入 -->

<bean id="car" class="cn.itcast.domain.Car">

<constructor-arg name="name" value="奥迪A6"></constructor-arg>

<constructor-arg name="price" value="57.3"></constructor-arg>

</bean>

  <!-- 第二种注入形式:set方法注入 -->

    <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="小明"></property>

    <property name="address" value="上海"></property>

    <property name="car" ref="car"></property>

</bean>

</beans>

n 在TestIOC中创建test2方法

@Test

public void test2(){

//创建Spring工厂(创建IOC容器)

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext2.xml");

People people = (People) ac.getBean("people");

System.out.println(people);

}


注意:采用set方法注入时,类中一定要有无参构造方法,因为spring会先调用无参构造方法实例化对象。

6.4. set方法其它注入写法

通过set方法注入还有其它两种写法,这两种写法都是spring在新的版本中提供的写法:

1、p命名空间的写法

2、SpEL的写法

applicationContext2.xml中引入p命名空间


6.4.1. p命名空间的写法

applicationContext2.xml中引入p命名空间


n 修改applicationContext2.xml,采用p命名空间的写法为People注入值。语法是:

p:简单属性名=”值”

p:对象属性名-ref=”beanid

<?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:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 构造方法注入 -->

<bean id="car" class="cn.itcast.domain.Car">

<constructor-arg name="name" value="奥迪A6"></constructor-arg>

<constructor-arg name="price" value="57.3"></constructor-arg>

</bean>

  <!-- 第二种注入形式:set方法注入 -->

    <!-- <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="小明"></property>

    <property name="address" value="上海"></property>

    <property name="car" ref="car"></property>

    </bean> -->

    <bean id="people" class="cn.itcast.domain.People" p:name="小刚" p:address="北京" p:car-ref="car"></bean>

</beans>

6.4.2. SpEL的写法(spring3.0提供)

什么是SpEl:Spring Expression Language

n 修改applicationContext2.xml,采用SpEL的写法为People注入值

<?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:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 构造方法注入 -->

<bean id="car" class="cn.itcast.domain.Car">

<constructor-arg name="name" value="奥迪A6"></constructor-arg>

<constructor-arg name="price" value="57.3"></constructor-arg>

</bean>

  <!-- 第二种注入形式:set方法注入 -->

    <!-- <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="小明"></property>

    <property name="address" value="上海"></property>

    <property name="car" ref="car"></property>

    </bean> -->

    <!-- <bean id="people" class="cn.itcast.domain.People" p:name="小刚" p:address="北京" p:car-ref="car"></bean> -->

     <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="#{'小明'}"></property>

    <property name="address" value="#{'上海'}"></property>

    <property name="car" value="#{car}"></property>

    </bean>

</beans>

SpEL注入的语法是:

注入字符串:#{‘字符串’}

注入数字:#{数字}

注入其它对象:#{对象id}

n SpEL还可以注入其它对象的属性或方法的返回值,创建CarInfo类,存储Car的信息:


public class CarInfo {

 

public String getCarName(){

return "宝骏560";

}

public double calculatePrice(){

return Math.random() * 10000;

}

}

创建Car2实体类


public class Car2 implements Serializable {

 

private static final long serialVersionUID = 1L;

private String name;

private Double price;

 

public void setName(String name) {

this.name = name;

}

 

 

public void setPrice(Double price) {

this.price = price;

}

 

 

@Override

public String toString() {

return "Car [name=" + name + ", price=" + price + "]";

}

 

}

在applicationContext2.xml配置Car2

<?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:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 构造方法注入 -->

<bean id="car" class="cn.itcast.domain.Car">

<constructor-arg name="name" value="奥迪A6"></constructor-arg>

<constructor-arg name="price" value="57.3"></constructor-arg>

</bean>

  <!-- 第二种注入形式:set方法注入 -->

    <!-- <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="小明"></property>

    <property name="address" value="上海"></property>

    <property name="car" ref="car"></property>

    </bean> -->

    <!-- <bean id="people" class="cn.itcast.domain.People" p:name="小刚" p:address="北京" p:car-ref="car"></bean> -->

     <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="#{'小明'}"></property>

    <property name="address" value="#{'上海'}"></property>

    <property name="car" value="#{car}"></property>

    </bean>

    

    <!-- SpEL的写法 -->

    <bean id="carInfo" class="cn.itcast.domain.CarInfo"></bean>

     <bean id="car2" class="cn.itcast.domain.Car2">

    <property name="name" value="#{carInfo.name}"></property>

    <property name="price" value="#{carInfo.calculatePrice()}"></property>

    </bean>

</beans>

注意:#{carInfo.carName}会调用getCarName方法获取汽车的名称;而#{carInfo.calculatePrice()}会直接调用calculatePrice方法获取汽车价格。

6.5. 数组或list注入(重点)

有的时候,bean中的属性是List或数组类型。那么该怎么给List或数组注入值呢?数组和list注入的写法是一样的。

n 新建bean类:CollectionBean


public class CollectionBean implements Serializable{

 

private static final long serialVersionUID = 1L;

private List<String> list;//也可以数组

public void setList(List<String> list) {

this.list = list;

}

@Override

public String toString() {

return "CollectionBean [list=" + list + "]";

}

}

applicationContext2.xml中配置CollectionBean

<?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:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 构造方法注入 -->

<bean id="car" class="cn.itcast.domain.Car">

<constructor-arg name="name" value="奥迪A6"></constructor-arg>

<constructor-arg name="price" value="57.3"></constructor-arg>

</bean>

  <!-- 第二种注入形式:set方法注入 -->

    <!-- <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="小明"></property>

    <property name="address" value="上海"></property>

    <property name="car" ref="car"></property>

    </bean> -->

    <!-- <bean id="people" class="cn.itcast.domain.People" p:name="小刚" p:address="北京" p:car-ref="car"></bean> -->

     <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="#{'小明'}"></property>

    <property name="address" value="#{'上海'}"></property>

    <property name="car" value="#{car}"></property>

    </bean>

    

    <!-- SpEL的写法 -->

    <bean id="carInfo" class="cn.itcast.domain.CarInfo"></bean>

     <bean id="car2" class="cn.itcast.domain.Car2">

    <property name="name" value="#{carInfo.name}"></property>

    <property name="price" value="#{carInfo.calculatePrice()}"></property>

    </bean>

    

    <!-- 特殊类型的注入 -->

    <bean id="cb" class="cn.itcast.domain.CollectionBean">

    <property name="list">

    <list>

    <value>乔峰</value>

    <value>段誉</value>

    <value>虚竹</value>

    </list>

    </property>

</bean>

</beans>

TestDI中创建单元测试方法test3:

@Test

public void test3(){

//创建Spring工厂(创建IOC容器)

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

CollectionBean cb = (CollectionBean) ac.getBean("cb");

System.out.println(cb);

}

测试结果如下:


6.6. Set集合的注入

有的时候,bean中的属性是Set类型。那么该怎么给Set类型的属性注入值呢?

修改CollectionBean,在其中添加一个Set类型的属性并提供set方法:

public class CollectionBean implements Serializable{

 

private static final long serialVersionUID = 1L;

private List<String> list;//也可以也成数组

private Set<String> set;

 

public void setList(List<String> list) {

this.list = list;

}

 

public void setSet(Set<String> set) {

this.set = set;

}

 

@Override

public String toString() {

return "CollectionBean [list=" + list + ", set=" + set + "]";

}

}

在applicaitonContext2.xml中为Set类型的属性注入值:

<?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:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 构造方法注入 -->

<bean id="car" class="cn.itcast.domain.Car">

<constructor-arg name="name" value="奥迪A6"></constructor-arg>

<constructor-arg name="price" value="57.3"></constructor-arg>

</bean>

  <!-- 第二种注入形式:set方法注入 -->

    <!-- <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="小明"></property>

    <property name="address" value="上海"></property>

    <property name="car" ref="car"></property>

    </bean> -->

    <!-- <bean id="people" class="cn.itcast.domain.People" p:name="小刚" p:address="北京" p:car-ref="car"></bean> -->

     <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="#{'小明'}"></property>

    <property name="address" value="#{'上海'}"></property>

    <property name="car" value="#{car}"></property>

    </bean>

    

    <!-- SpEL的写法 -->

    <bean id="carInfo" class="cn.itcast.domain.CarInfo"></bean>

     <bean id="car2" class="cn.itcast.domain.Car2">

    <property name="name" value="#{carInfo.name}"></property>

    <property name="price" value="#{carInfo.calculatePrice()}"></property>

    </bean>

    

    <!-- 特殊类型的注入 -->

    <bean id="cb" class="cn.itcast.domain.CollectionBean">

    <property name="list">

    <list>

    <value>乔峰</value>

    <value>段誉</value>

    <value>虚竹</value>

    </list>

    </property>

    <property name="set">

    <set>

    <value>鸠摩智</value>

    <value>天山童姥</value>

    <value>无崖子</value>

    </set>

    </property>

    </bean>

</beans>

提示:spring在注入set的时,给我们注入的是一个LinkedHashSet,所以在输入set集合中的元素时,是按照我们注入的顺序来的,并不是无序的。

6.7. Map集合的注入

有的时候,bean中的属性是Map类型。那么该怎么给Map类型的属性注入值呢?

修改CollectionBean,在其中添加一个Map类型的属性并提供set方法:

public class CollectionBean implements Serializable{

 

/**

 *

 */

private static final long serialVersionUID = 1L;

private List<String> list;//也可以也成数组

private Set<String> set;

private Map<String,String> map;

 

public void setList(List<String> list) {

this.list = list;

}

 

public void setSet(Set<String> set) {

this.set = set;

}

public void setMap(Map<String, String> map) {

this.map = map;

}

 

@Override

public String toString() {

return "CollectionBean [list=" + list + ", set=" + set + ", map=" + map + "]";

}

 

}

在applicationContext2.xml中为Map输入注入值:

<?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:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 构造方法注入 -->

<bean id="car" class="cn.itcast.domain.Car">

<constructor-arg name="name" value="奥迪A6"></constructor-arg>

<constructor-arg name="price" value="57.3"></constructor-arg>

</bean>

  <!-- 第二种注入形式:set方法注入 -->

    <!-- <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="小明"></property>

    <property name="address" value="上海"></property>

    <property name="car" ref="car"></property>

    </bean> -->

    <!-- <bean id="people" class="cn.itcast.domain.People" p:name="小刚" p:address="北京" p:car-ref="car"></bean> -->

     <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="#{'小明'}"></property>

    <property name="address" value="#{'上海'}"></property>

    <property name="car" value="#{car}"></property>

    </bean>

    

    <!-- SpEL的写法 -->

    <bean id="carInfo" class="cn.itcast.domain.CarInfo"></bean>

     <bean id="car2" class="cn.itcast.domain.Car2">

    <property name="name" value="#{carInfo.name}"></property>

    <property name="price" value="#{carInfo.calculatePrice()}"></property>

    </bean>

    

    <!-- 特殊类型的注入 -->

    <bean id="cb" class="cn.itcast.domain.CollectionBean">

    <property name="list">

    <list>

    <value>乔峰</value>

    <value>段誉</value>

    <value>虚竹</value>

    </list>

    </property>

    <property name="set">

    <set>

    <value>鸠摩智</value>

    <value>天山童姥</value>

    <value>无崖子</value>

    </set>

    </property>

    <property name="map">

    <map>

    <entry key="id" value="1"></entry>

    <entry key="username" value="张三"></entry>

    </map>

    </property>

</bean>

</beans>

说明:

<entry>表示map中的一个键值对;

<entry>key表示键,value表示值;

6.8. Properties的注入(重点)

有的时候,bean中的属性是Properties类型。那么该怎么给Properties类型的属性注入值呢?

修改CollectionBean,在其中添加一个Properties类型的属性并提供set方法:

public class CollectionBean implements Serializable{

 

/**

 *

 */

private static final long serialVersionUID = 1L;

private List<String> list;//也可以也成数组

private Set<String> set;

private Map<String,String> map;

private Properties properties;

 

public void setList(List<String> list) {

this.list = list;

}

 

public void setSet(Set<String> set) {

this.set = set;

}

public void setMap(Map<String, String> map) {

this.map = map;

}

public void setProperties(Properties properties) {

this.properties = properties;

}

 

@Override

public String toString() {

return "CollectionBean [list=" + list + ", set=" + set + ", map=" + map + ", properties=" + properties + "]";

}

 

}

在applicationContext2.xml中给Properties类型的属性注入值:

 <?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:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 构造方法注入 -->

<bean id="car" class="cn.itcast.domain.Car">

<constructor-arg name="name" value="奥迪A6"></constructor-arg>

<constructor-arg name="price" value="57.3"></constructor-arg>

</bean>

  <!-- 第二种注入形式:set方法注入 -->

    <!-- <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="小明"></property>

    <property name="address" value="上海"></property>

    <property name="car" ref="car"></property>

    </bean> -->

    <!-- <bean id="people" class="cn.itcast.domain.People" p:name="小刚" p:address="北京" p:car-ref="car"></bean> -->

     <bean id="people" class="cn.itcast.domain.People">

    <property name="name" value="#{'小明'}"></property>

    <property name="address" value="#{'上海'}"></property>

    <property name="car" value="#{car}"></property>

    </bean>

    

    <!-- SpEL的写法 -->

    <bean id="carInfo" class="cn.itcast.domain.CarInfo"></bean>

     <bean id="car2" class="cn.itcast.domain.Car2">

    <property name="name" value="#{carInfo.name}"></property>

    <property name="price" value="#{carInfo.calculatePrice()}"></property>

    </bean>

    

    <!-- 特殊类型的注入 -->

    <bean id="cb" class="cn.itcast.domain.CollectionBean">

    <property name="list">

    <list>

    <value>乔峰</value>

    <value>段誉</value>

    <value>虚竹</value>

    </list>

    </property>

    <property name="set">

    <set>

    <value>鸠摩智</value>

    <value>天山童姥</value>

    <value>无崖子</value>

    </set>

    </property>

    <property name="map">

    <map>

    <entry key="id" value="1"></entry>

    <entry key="username" value="张三"></entry>

    </map>

    </property>

    <property name="properties">

    <props>

    <prop key="id">2</prop>

    <prop key="name">小明</prop>

    </props>

    </property>

    </bean>

</beans>

说明:

<prop>:表示一个键值对;

<prop>中的key表示键,在<prop></prop>中写的是值;

6.9. 配置文件的分离

在实际开发时,会有很多个bean都需要配置在spring中。但是,如果把所有的bean都配置在applicationContext.xml中,applicationContext.xml就会变得很庞大,不便于修改与维护。可以把spring的配置文件进行分离:

Spring配置文件的分离有两种方式:

方式一:在applicationContext.xml中采用import标签导入另一个配置文件

现在,在整个工程中有applicationContext.xmlapplicationContext2.xml两个配置文件。可以把aplicationContext.xml看成一个总的配置文件,在其中包含applicaitonContext2.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">

 

<bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl"

init-method="init" destroy-method="destroy"></bean>

<!-- <bean id="deptDao" class="cn.itcast.factory.Factory" factory-method="create"></bean> -->

<!-- 实例工厂方法来实例化 -->

<bean id="factory" class="cn.itcast.factory.Factory"></bean>

<bean id="deptDao" factory-bean="factory" factory-method="create"></bean>

<!-- 构造方法注入 -->

<bean id="car" class="cn.itcast.domain.Car">

<constructor-arg name="name" value="奥迪A6"></constructor-arg>

<constructor-arg name="price" value="57.3"></constructor-arg>

</bean>

<import resource="applicationContext2.xml"/>

</beans>

此时,创建IOC容器时,只需要加载applicationContext.xml即可,因为在applicationContext.xml引入了applicationContext2.xml文件,所以,applicationContext2.xml也会加载。

方式二:在实例化ApplicationContext的时候,指定多个配置文件。修改TestIOC中的test4方法,创建ApplicationContext时同时加载多个文件:

@Test

public void test4(){

//创建Spring工厂(创建IOC容器)

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml");

DeptDao deptDao = (DeptDao) ac.getBean("deptDao");

deptDao.save();

}

7. 附录:开闭原则



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
探索全栈前端技术的魅力:HTML+CSS+JS+JQ+Bootstrap网站源码深度解析 在这个数字化时代,构建一个既美观又功能强大的网站成为了许多开发者和企业追逐的目标。本份资源精心汇集了一套完整网站源码,融合了HTML的骨架搭建、CSS的视觉美化、JavaScript的交互逻辑、jQuery的高效操作以及Bootstrap的响应式设计,全方位揭秘了现代网页开发的精髓。 HTML,作为网页的基础,它构建了信息的框架;CSS则赋予网页生动的外观,让设计创意跃然屏上;JavaScript的加入,使网站拥有了灵动的交互体验;jQuery,作为JavaScript的强力辅助,简化了DOM操作与事件处理,让编码更为高效;而Bootstrap的融入,则确保了网站在不同设备上的完美呈现,响应式设计让访问无界限。 通过这份源码,你将: 学习如何高效组织HTML结构,提升页面加载速度与SEO友好度; 掌握CSS高级技巧,如Flexbox与Grid布局,打造适应各种屏幕的视觉盛宴; 理解JavaScript核心概念,动手实现动画、表单验证等动态效果; 利用jQuery插件快速增强用户体验,实现滑动效果、Ajax请求等; 深入Bootstrap框架,掌握移动优先的开发策略,响应式设计信手拈来。 无论是前端开发新手渴望系统学习,还是资深开发者寻求灵感与实用技巧,这份资源都是不可多得的宝藏。立即深入了解,开启你的全栈前端探索之旅,让每一个网页都成为技术与艺术的完美融合!
探索全栈前端技术的魅力:HTML+CSS+JS+JQ+Bootstrap网站源码深度解析 在这个数字化时代,构建一个既美观又功能强大的网站成为了许多开发者和企业追逐的目标。本份资源精心汇集了一套完整网站源码,融合了HTML的骨架搭建、CSS的视觉美化、JavaScript的交互逻辑、jQuery的高效操作以及Bootstrap的响应式设计,全方位揭秘了现代网页开发的精髓。 HTML,作为网页的基础,它构建了信息的框架;CSS则赋予网页生动的外观,让设计创意跃然屏上;JavaScript的加入,使网站拥有了灵动的交互体验;jQuery,作为JavaScript的强力辅助,简化了DOM操作与事件处理,让编码更为高效;而Bootstrap的融入,则确保了网站在不同设备上的完美呈现,响应式设计让访问无界限。 通过这份源码,你将: 学习如何高效组织HTML结构,提升页面加载速度与SEO友好度; 掌握CSS高级技巧,如Flexbox与Grid布局,打造适应各种屏幕的视觉盛宴; 理解JavaScript核心概念,动手实现动画、表单验证等动态效果; 利用jQuery插件快速增强用户体验,实现滑动效果、Ajax请求等; 深入Bootstrap框架,掌握移动优先的开发策略,响应式设计信手拈来。 无论是前端开发新手渴望系统学习,还是资深开发者寻求灵感与实用技巧,这份资源都是不可多得的宝藏。立即深入了解,开启你的全栈前端探索之旅,让每一个网页都成为技术与艺术的完美融合!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值