Spring First《基于eclipse Myeclipse idea》开发

1.1.1 spring介绍

Spring是分层的Java SE/EE应用 full-stack轻量级开源框架,以IoC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架。

1.1.2 Spring的发展历程

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雏形)

1.1.3 spring的优势

方便解耦,简化开发
通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
AOP编程的支持
通过Spring的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。
方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。
方便集成各种优秀框架
Spring可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持。
降低JavaEE API的使用难度
Spring对JavaEE API(如JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低。
Java源码是经典学习范例
Spring的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。它的源代码无意是Java技术的最佳实践的范例。

Spring是什么?

在这里插入图片描述
在这里插入图片描述

1.1.4 spring的体系结构

在这里插入图片描述

1.2 程序的耦合和解耦

1.2.1 什么是程序的耦合

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

/**
 * 客户的业务层实现类
 */
public class CustomerServiceImpl implements ICustomerService {
	
	private ICustomerDao customerDao = new CustomerDaoImpl();	
}

上面的代码表示:业务层调用持久层,并且此时业务层在依赖持久层的接口和实现类。如果此时没有持久层实现类,编译将不能通过。这种依赖关系就是我们可以通过优化代码解决的。
再比如:
下面的代码中,我们的类依赖了MySQL的具体驱动类,如果这时候更换了数据库品牌,我们需要改源码来修改数据库驱动。这显然不是我们想要的。

public class JdbcDemo1 {
	
	/**
	 * JDBC操作数据库的基本入门中存在什么问题?
	 * 	  导致驱动注册两次是个问题,但不是严重的。
	 * 	  严重的问题:是当前类和mysql的驱动类有很强的依赖关系。
	 * 			     当我们没有驱动类的时候,连编译都不让。
	 * 那这种依赖关系,就叫做程序的耦合
	 * 
	 * 我们在开发中,理想的状态应该是:
	 * 	  我们应该尽力达到的:编译时不依赖,运行时才依赖。
	 * 	 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		//1.注册驱动
		//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
		Class.forName("com.mysql.jdbc.Driver");
		//2.获取连接
		//3.获取预处理sql语句对象
		//4.获取结果集
		//5.遍历结果集
	}
}

1.2.2 解决程序耦合的思路

当是我们讲解jdbc时,是通过反射来注册驱动的,代码如下:

Class.forName(“com.mysql.jdbc.Driver”);
这时的好处是,我们的类中不再依赖具体的驱动类,此时就算删除mysql的驱动jar包,依然可以编译。但是因为没有驱动类,所以不能运行。
不过,此处也有个问题,就是我们反射类对象的全限定类名字符串是在java类中写死的,一旦要改还是要修改源码。
解决这个问题也很简单,使用配置文件配置。

1.2.3 工厂模式解耦

在实际开发中我们可以把所有的dao和service和action对象使用配置文件配置起来,当启动服务器应用加载的时候,通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。

1.2.4 控制反转-Inversion Of Control

上面解耦的思路有2个问题:
1、存哪去?
分析:由于我们是很多对象,肯定要找个集合来存。这时候有Map和List供选择。
到底选Map还是List就看我们有没有查找需求。有查找需求,选Map。
所以我们的答案就是
在应用加载时,创建一个Map,用于存放action,Service和dao对象。
我们把这个map称之为容器。
2、还是没解释什么是工厂?
工厂就是负责给我们从容器中获取指定对象的类。这时候我们获取对象的方式发生了改变。
原来:
我们在获取对象时,都是采用new的方式。是主动的

在这里插入图片描述
现在:
我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象。是被动的
在这里插入图片描述
这种被动接收的方式获取对象的思想就是控制反转,它是spring框架的核心之一。
它的作用只有一个:削减计算机程序的耦合。
在这里插入图片描述

控制反转IOC和依赖注入DI

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
IOC和DI 【重点】
1.IOC(Inverse Of Control)称为控制反转: 是指将创建对象的权利由程序员反转给了Spring工厂管理。
2.DI(Dependency Injection)称为依赖注入:是指Spring工厂创建对象的同时,可以给对象依赖的属性注入值。
3. 基于IOC和DI的思想开发的好处:
3.1 使我们的对象之间的依赖关系做到了弱耦合。
3.2 利于项目的维护和升级。

Spring框架采用了很多的设计模式 : 单例模式、工厂模式、代理模式、适配器模式、观察者模式、策略模式、装饰器模式等等。

二、工厂设计模式实践

  1. 工厂设计模式主要目的是通过工厂类生产对象。
  2. 工厂实践的步骤:
    2.1 编写工厂配置文件 : 配置需要工厂创建的对象的基本信息
    2.2 创建工厂,从工厂中获取对象
  3. 使用工厂模式有什么好处:
    我们可以将一些对象创建的过程封装在工厂类中, 使用者只需要从工厂中获取就可以。使我们对于对象的创建变得更加灵活。

使用spring的IOC解决程序耦合

本章我们使用的案例是,客户的业务层和持久层的依赖关系解决。在开始spring的配置之前,我们要先准备一下环境。由于我们是使用spring解决依赖关系,并不是真正的要做增伤改查操作,所以此时我们没必要写实体类。并且我们在此处使用的是java工程,不是java web工程。

2.1.1 准备spring的开发包

官网:http://spring.io/
下载地址:
http://repo.springsource.org/libs-release-local/org/springframework/spring
解压:(Spring目录结构:)

  • docs :API和开发规范.
  • libs :jar包和源码.
  • schema :约束.
    版本是spring4.2.4。
    (在最后会附上maven的依赖配置pom.xml)
    在这里插入图片描述

2.3 Spring基于XML的IOC细节

2.3.1 spring中工厂的类结构图

在这里插入图片描述

2.3.1.1 BeanFactory和ApplicationContext的区别

BeanFactory才是Spring容器中的顶层接口。
ApplicationContext是它的子接口。
BeanFactory和ApplicationContext的区别:
创建对象的时间点不一样。
ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
BeanFactory:什么使用什么时候创建对象。

2.3.1.2 ApplicationContext接口的实现类

ApplicationContext的实现类,如下图:
在这里插入图片描述
ClassPathXmlApplicationContext:
它是从类的根路径下加载配置文件 推荐使用这种
FileSystemXmlApplicationContext:
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。

2.3.2 IOC中bean标签和管理对象细节

2.3.2.1 bean标签

  • 作用:
    用于配置对象让spring来创建的。
    默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。

  • 属性:
    id:给对象在容器中提供一个唯一标识。用于获取对象。
    class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
    scope:指定对象的作用范围。
    * singleton :默认值,单例的.
    * prototype :多例的.
    * request :WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中.
    * session :WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中.
    * globalSession :WEB项目中,应用在Portlet环境.如果没有Portlet环境那么globalSession相当于session.

    init-method:指定类中的初始化方法名称。
    destroy-method:指定类中销毁方法名称。

2.3.2.2 bean的作用范围和生命周期

  • 单例对象:scope=“singleton”
    一个应用只有一个对象的实例。它的作用范围就是整个引用。
    生命周期:
    对象出生:当应用加载,创建容器时,对象就被创建了。
    对象活着:只要容器在,对象一直活着。
    对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
  • 多例对象:scope=“prototype”
    每次访问对象时,都会重新创建对象实例。
    生命周期:
    对象出生:当使用对象时,创建新的对象实例。
    对象活着:只要对象在使用中,就一直活着。
    对象死亡:当对象长时间不用时,被java的垃圾回收器回收了。

Spring工厂创建对象的生命周期:【掌握】

1. 创建的时机:
	1.1 Spring在工厂初始化的时候,会创建所有的单例对象。
	1.2 对于多例的对象,在从工厂获取的时候才会创建。
2. 销毁:
	2.1 在Spring工厂关闭的时候销毁所有的单例对象。
	2.2 对于多例对象的销毁Spring工厂不去管理。

2.3.2.3 实例化Bean的三种方式

第一种方式:使用默认无参构造函数
	<!--在默认情况下:
		它会根据默认无参构造函数来创建类对象。如果bean中没有默认无参构造函数,将会创建失败。 
	-->
<bean id="customerService" class="com.itheima.service.impl.CustomerServiceImpl"/>
第二种方式:spring管理静态工厂-使用静态工厂的方法创建对象
/**
 * 模拟一个静态工厂,创建业务层实现类
 */
public class StaticFactory {	
	public static ICustomerService createCustomerService(){
		return new CustomerServiceImpl();
	}
}
<!-- 此种方式是:
	 使用StaticFactory类中的静态方法createCustomerService创建对象,并存入spring容器
	 id属性:指定bean的id,用于从容器中获取
	 class属性:指定静态工厂的全限定类名
	 factory-method属性:指定生产对象的静态方法
 -->
<bean id="customerService" 
	  class="com.itheima.factory.StaticFactory" 
	  factory-method="createCustomerService"></bean>


第三种方式:spring管理实例工厂-使用实例工厂的方法创建对象
/**
 * 模拟一个实例工厂,创建业务层实现类
 * 此工厂创建对象,必须现有工厂实例对象,再调用方法
 */
public class InstanceFactory {	
	public ICustomerService createCustomerService(){
		return new CustomerServiceImpl();
	}
}
	<!-- 此种方式是:
		 先把工厂的创建交给spring来管理。
		然后在使用工厂的bean来调用里面的方法
		factory-bean属性:用于指定实例工厂bean的id。
		factory-method属性:用于指定实例工厂中创建对象的方法。
	-->
	<bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean>
	<bean id="customerService" 
		  factory-bean="instancFactory" 
		  factory-method="createCustomerService"></bean>

2.3.3 spring的依赖注入

Spring中的注入方式:

set注入、构造注入、自动注入 。

2.3.3.1 依赖注入的概念

它是spring框架核心ioc的具体实现方式。简单的说,就是坐等框架把对象传入,而不用我们自己去获取。

2.3.3.2 构造函数注入

顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让spring框架来为我们注入。具体代码如下:
三种
在这里插入图片描述

/**
 */
public class CustomerServiceImpl implements ICustomerService {
	
	private String name;
	private Integer age;
	private Date birthday;
		
	public CustomerServiceImpl(String name, Integer age, Date birthday) {
		this.name = name;
		this.age = age;
		this.birthday = birthday;
	}

	@Override
	public void saveCustomer() {
		System.out.println(name+","+age+","+birthday);	
	}
}

<!-- 使用构造函数的方式,给service中的属性传值
	要求:
		类中需要提供一个对应参数列表的构造函数。
	涉及的标签:
		constructor-arg
			属性:
				index:指定参数在构造函数参数列表的索引位置
				type:指定参数在构造函数中的数据类型
				name:指定参数在构造函数中的名称					用这个找给谁赋值
				
				=======上面三个都是找给谁赋值,下面两个指的是赋什么值的==============
				
				value:它能赋的值是基本数据类型和String类型
				ref:它能赋的值是其他bean类型,也就是说,必须得是在配置文件中配置过的bean
	 -->
<bean id="customerService" class="com.itheima.service.impl.CustomerServiceImpl">
	<constructor-arg name="name" value="张三"></constructor-arg>
	<constructor-arg name="age" value="18"></constructor-arg>
	<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>

<bean id="now" class="java.util.Date"></bean>

自动注入

  1. 自动注入 : 【了解】
    5.1 根据名字进行匹配
    5.2 根据类型匹配
    在这里插入图片描述
    在这里插入图片描述

PS: 由于自动注入的实现过程是 通过到Spring工厂中寻找指定的对象进行注入, 所以自动注入只适用于自定义对象类型属性的注入(交给工厂管理的对象才能使用自动注入)。

2.3.3.3 set方法注入

在这里插入图片描述

顾名思义,就是在类中提供需要注入成员的set方法。具体代码如下:

/**
 */
public class CustomerServiceImpl implements ICustomerService {
	
	private String name;
	private Integer age;
	private Date birthday;
	
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	@Override
	public void saveCustomer() {
		System.out.println(name+","+age+","+birthday);	
	}
}

<!-- 通过配置文件给bean中的属性传值:使用set方法的方式
	涉及的标签:
		property
		属性:
			name:找的是类中set方法后面的部分
			ref:给属性赋值是其他bean类型的
			value:给属性赋值是基本数据类型和string类型的
	实际开发中,此种方式用的较多。
-->
<bean id="customerService" class="com.itheima.service.impl.CustomerServiceImpl">
		<property name="name" value="test"></property>
		<property name="age" value="21"></property>
		<property name="birthday" ref="now"></property>
</bean>
	
<bean id="now" class="java.util.Date"></bean>

2.3.3.4 使用p名称空间注入数据(本质还是调用set方法)

此种方式是通过在xml中导入p名称空间,使用p:propertyName来注入数据,它的本质仍然是调用类中的set方法实现注入功能。

/**
 * 使用p名称空间注入,本质还是调用类中的set方法
 */
public class CustomerServiceImpl4 implements ICustomerService {
	
	private String name;
	private Integer age;
	private Date birthday;
	
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	@Override
	public void saveCustomer() {
		System.out.println(name+","+age+","+birthday);	
	}
}
配置文件代码:
<beans xmlns="http://www.springframework.org/schema/beans"
	    xmlns:p="http://www.springframework.org/schema/p"
         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="customerService" 
		  class="com.itheima.service.impl.CustomerServiceImpl4"
		  p:name="test" p:age="21" p:birthday-ref="now"/>
</beans>

2.3.3.5 注入集合属性

顾名思义,就是给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。我们这里介绍注入数组,List,Set,Map,Properties。具体代码如下:


/**
 */
public class CustomerServiceImpl implements ICustomerService {
	
	private String[] myStrs;
	private List<String> myList;
	private Set<String> mySet;
	private Map<String,String> myMap;
	private Properties myProps;
	
	public void setMyStrs(String[] myStrs) {
		this.myStrs = myStrs;
	}
	public void setMyList(List<String> myList) {
		this.myList = myList;
	}
	public void setMySet(Set<String> mySet) {
		this.mySet = mySet;
	}
	public void setMyMap(Map<String, String> myMap) {
		this.myMap = myMap;
	}
	public void setMyProps(Properties myProps) {
		this.myProps = myProps;
	}

	@Override
	public void saveCustomer() {
		System.out.println(Arrays.toString(myStrs));
		System.out.println(myList);
		System.out.println(mySet);
		System.out.println(myMap);
		System.out.println(myProps);
	}
}
	
<!-- 注入集合数据 
	 List结构的:
		array,list,set
	Map结构的
		map,entry,props,prop
-->
<bean id="customerService" class="com.itheima.service.impl.CustomerServiceImpl">
	<!-- 在注入集合数据时,只要结构相同,标签可以互换 -->
	<!-- 给数组注入数据 -->
	<property name="myStrs">
		<set>
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</set>
	</property>
	<!-- 注入list集合数据 -->
	<property name="myList">
		<array>
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</array>
	</property>
	<!-- 注入set集合数据 -->
	<property name="mySet">
		<list>
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</list>
	</property>
	<!-- 注入Map数据 -->
	<property name="myMap">
		<props>
			<prop key="testA">aaa</prop>
			<prop key="testB">bbb</prop>
		</props>
	</property>
	<!-- 注入properties数据 -->
	<property name="myProps">
		<map>
			<entry key="testA" value="aaa"></entry>
			<entry key="testB">
				<value>bbb</value>
			</entry>
		</map>
	</property>
</bean>

在这里插入图片描述

一些Bean的配置

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Eclipse开发安装插件

在这里插入图片描述

Myecclipse引入DTD

3.1 Spring配置文件中提示的配置
在这里插入图片描述
在这里插入图片描述

补充 SPEL

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

扫描注解开发Bean

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Spring4特性

在这里插入图片描述

基于注解的IOC配置详情

1.2 环境搭建

1.2.1 第一步:拷贝必备jar包到工程的lib目录。

在这里插入图片描述

1.2.2 第二步:在类的根路径下创建一个任意名称的xml文件(不能是中文)

基于注解整合时,导入约束时需要多导入一个context名称空间下的约束。
<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入schema 
约束的位置在:
	..\spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html
	文件中。
注意:要导入schema约束
-->
<beans xmlns="http://www.springframework.org/schema/beans"
	  xmlns:context="http://www.springframework.org/schema/context"
       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
				http://www.springframework.org/schema/context
      			http://www.springframework.org/schema/context/spring-context.xsd ">

1.2.3 第三步:使用@Component注解配置管理的资源

/**

  • 客户的业务层实现类
  • @author zhy

@Component(value=“customerService”)
public class CustomerServiceImpl implements ICustomerService {
@Override
public void saveCustomer() {
System.out.println(“执行了保存客户”);
}
}

1.2.4 第四步在spring的配置文件中开启spring对注解ioc的支持
<!-- 告知spring框架在,读取配置文件,创建容器时,扫描注解,依据注解创建对象,并存入容器中 -->
	<context:component-scan base-package="com.itheima"></context:component-scan>

1.3 常用注解

1.3.1 用于创建对象的
	相当于:<bean id="" class="">

1.3.1.1 @Component

作用:
把资源让spring来管理。相当于在xml中配置一个bean。
属性:
value:指定bean的id。如果不指定value属性,默认bean的id是当前类的类名。首字母小写。

1.3.1.2 @Controller @Service @Repository

他们三个注解都是针对一个的衍生注解,他们的作用及属性都是一模一样的。
他们只不过是提供了更加明确的语义化。
@Controller:一般用于表现层的注解。
@Service:一般用于业务层的注解。
@Repository:一般用于持久层的注解。
细节:如果注解中有且只有一个属性要赋值时,且名称是value,value在赋值是可以不写。

1.3.2 用于注入数据的
相当于:<property name="" ref=""> 	   
			<property name="" value="">
1.3.2.1 @Autowired

作用:
自动按照类型注入。当使用注解注入属性时,set方法可以省略。它只能注入其他bean类型。当有多个类型匹配时,使用要注入的对象变量名称作为bean的id,在spring容器查找,找到了也可以注入成功。找不到就报错。

1.3.2.2 @Qualifier

作用:
在自动按照类型注入的基础之上,再按照Bean的id注入。它在给字段注入时不能独立使用,必须和@Autowire一起使用;但是给方法参数注入时,可以独立使用。
属性:
value:指定bean的id。

1.3.2.3 @Resource

作用:
直接按照Bean的id注入。它也只能注入其他bean类型。
属性:
name:指定bean的id。

1.3.2.4 @Value

作用:
注入基本数据类型和String类型数据的
属性:
value:用于指定值

1.3.3 用于改变作用范围的:
相当于:<bean id="" class="" scope="">
1.3.3.1 @Scope

作用:
指定bean的作用范围。
属性:
value:指定范围的值。
取值:singleton prototype request session globalsession

1.3.4 和生命周期相关的:(了解)
相当于:<bean id="" class="" init-method="" destroy-method="" />
1.3.4.1 @PostConstruct

作用:
用于指定初始化方法。

1.3.4.2 @PreDestroy

作用:
用于指定销毁方法。

1.3.5 代码示例
业务层代码:
/**
 * 客户的业务层接口
 */
public interface ICustomerService {	
	/**
	 * 保存客户
	 * @param customer
	 */
	void saveCustomer();	
}


/**
 * 客户的业务层实现类
 */
//作用就相当于在xml中配置了一个bean标签,该注解有value属性,含义是bean的id。
//不写的时候,默认的id是:当前类名,且首字母小写。即:customerServiceImpl
@Component(value="customerService")
@Scope(value="singleton")
public class CustomerServiceImpl implements ICustomerService {
//	@Autowired
//	自动按照数据类型注入,拿着当前变量的数据类型在spring的容器中找,找到后,给变量赋值。
//	当有多个类型匹配时,会使用当前变量名称customerDao作为bean的id,继续在容器中找。
//	找到了,也能注入成功。找不到就报错。
//	@Qualifier(value="customerDao2")//在自动按照类型注入的基础之上,再按照id注入
	@Resource(name="customerDao2")//直接按照bean的id注入
	private ICustomerDao customerDao = null;
	
	@Value("com.mysql.jdbc.Driver")//注入基本类型和String类型数据
	private String driver;

	@Override
	public void saveCustomer() {
		System.out.println(driver);
		customerDao.saveCustomer();	
	}
}


持久层代码:
/**
 * 客户的持久层接口
 */
public interface ICustomerDao {
	/**
	 * 保存客户
	 */
	void saveCustomer();
}



/**
 * 客户的持久层实现类11111111111111111111
 */
@Repository("customerDao1")
public class CustomerDaoImpl implements ICustomerDao {

	@Override
	public void saveCustomer() {
		System.out.println("保存了客户111111111111111111");
	}
}

/**
 * 客户的持久层实现类222222222222222222222222
 */
@Repository("customerDao2")
public class CustomerDaoImpl2 implements ICustomerDao {

	@Override
	public void saveCustomer() {
		System.out.println("保存了客户2222222222222222222");
	}
}

测试类代码:
public class Client {
	public static void main(String[] args) {
		//1.获取容器
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		//2.根据id获取对象
		ICustomerService cs = (ICustomerService) ac.getBean("customerService");				cs.saveCustomer();
	}
}

配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 我们导入约束时,除了昨天的那部分之外,还要单独导入一个context名称空间 -->
<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">
	<!-- 告知spring框架在通过读取配置文件创建容器时,扫描的包,并根据包中类的注解创建对象-->
	<context:component-scan base-package="com.itheima"></context:component-scan>
</beans>

1.3.6 关于Spring注解和XML的选择问题

注解的优势:
配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。
XML的优势:
修改时,不用改源码。不涉及重新编译和部署。
在这里插入图片描述

1.4 spring管理对象细节

基于注解的spring IoC配置中,bean对象的特点和基于XML配置是一模一样的。
写到此处,基于注解的IoC配置已经完成,但是大家都发现了一个问题:我们依然离不开spring的xml配置文件,那么能不能不写这个bean.xml,所有配置都用注解来实现呢?
答案是肯定的,请看下一章节。

1.5 spring的纯注解配置

1.5.1 待改造的问题

我们发现,之所以我们现在离不开xml配置文件,是因为我们有一句很关键的配置:
<!-- 告知spring框架在,读取配置文件,创建容器时,扫描注解,依据注解创建对象,并存入容器中 -->
	<context:component-scan base-package="com.itheima"></context:component-scan>
如果他要也能用注解配置,那么我们就可以脱离xml文件了。

在这里插入图片描述

/**
 * 客户的业务层实现类
 */
@Configuration//表明当前类是一个配置类
@ComponentScan(basePackages = "com.itheima")//配置要扫描的包
public class SpringConfiguration {
}

那么新的问题又来了,我们如何获取容器呢?
public class Client {
	public static void main(String[] args) {
		//1.获取容器:由于我们已经没有了xml文件,所以再用读取xml方式就不能用了。
		//这时需要指定加载哪个类上的注解
		ApplicationContext ac = 
			new AnnotationConfigApplicationContext(SpringConfiguration.class);
		//2.根据id获取对象
		ICustomerService cs = (ICustomerService) ac.getBean("customerService");
		cs.saveCustomer();
	}
}

1.5.3 新注解说明

1.5.3.1 @Configuration
作用:
	用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration注解的类.class)。
属性:
	value:用于指定配置类的字节码
示例代码:
/**
 * 用于初始化spring容器的配置类
 */
@Configuration
public class SpringConfiguration{
}
1.5.3.2 @ComponentScan

作用:
用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的:
<context:component-scan base-package=“com.itheima”/>是一样的。
属性:
basePackages:用于指定要扫描的包。和该注解中的value属性作用一样。

1.5.3.3 @PropertySource

作用:
用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置。
属性:
value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:
示例代码:
配置:
public class JdbcConfig {

@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;

@Bean(name="dataSource")
public DataSource getDataSource(){
	BasicDataSource ds = new BasicDataSource();
	ds.setDriverClassName(driver);
	ds.setUrl(url);
	ds.setUsername(username);
	ds.setPassword(password);
	return ds;
}	

}
jdbc.properties文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/day44_ee247_spring
jdbc.username=root
jdbc.password=1234

注意:
使用的版本是4.2.4,在spring4.3以前都需要提供一个占位符配置器:
PropertySourcesPlaceholderConfigurer
而在spring4.3以后,则不需要提供。
提供的方式如下:(在SpringConfiguration或JdbcConfig中配置均可)
@Bean
public static PropertySourcesPlaceholderConfigurer
propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}

1.5.3.3 1.5.3.4 @Import

作用:
用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。当然,写上也没问题。
属性:
value[]:用于指定其他配置类的字节码。
示例代码:
@Configuration
@ComponentScan(basePackages = “cn.itcast.spring”)
@Import({ Configuration_B.class})
public class Configuration_A {
}

@Configuration
@PropertySource(“classpath:info.properties”)
public class Configuration_B {

}

1.5.3.3 1.5.3.5 @Bean

作用:
该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。它就相当于我们之前在xml配置中介绍的factory-bean和factory-method。
属性:
name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。
示例代码:
@Bean(name = “datasource2”)
public DataSource createDS() throws Exception {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setUser(“root”);
comboPooledDataSource.setPassword(“1234”);
comboPooledDataSource.setDriverClass(“com.mysql.jdbc.Driver”);
comboPooledDataSource.setJdbcUrl(“jdbc:mysql:///spring_ioc”);
return comboPooledDataSource;

第2章 Spring整合Junit

2.1 准备测试环境
2.1.1 创建业务层接口实现类
/**
 * 客户的业务层接口
 */
public interface ICustomerService {

	/**
	 * 查询所有客户
	 * @return
	 */
	List<Customer> findAllCustomer();
	
	/**
	 * 保存客户
	 * @param customer
	 */
	void saveCustomer(Customer customer);
}

/**
 * 客户的业务层实现类
 */
public class CustomerServiceImpl implements ICustomerService {

	private ICustomerDao customerDao;
	
	public void setCustomerDao(ICustomerDao customerDao) {
		this.customerDao = customerDao;
	}

	@Override
	public List<Customer> findAllCustomer() {
		return customerDao.findAllCustomer();
	}

	@Override
	public void saveCustomer(Customer customer) {
		customerDao.save(customer);
	}

}
2.1.2	创建持久层接口实现类
/**
 * 客户的持久层接口
 */
public interface ICustomerDao {
	
	/**
	 * 查询所有客户
	 * @return
	 */
	List<Customer> findAllCustomer();

	/**
	 * 保存客户
	 * @param customer
	 */
	void save(Customer customer);
}

/**
 * 客户的持久层实现类
 */
public class CustomerDaoImpl implements ICustomerDao {

	@Override
	public List<Customer> findAllCustomer() {
		System.out.println("查询了所有客户");
		return null;
	}

	@Override
	public void save(Customer customer) {
		System.out.println("保存了客户");
	}
}

2.1.3 导入junit的jar包

在这里插入图片描述

2.1.4 编写测试类

/**
 * 测试客户的业务层和持久层
 */
public class CustomerServiceTest {

	private ICustomerService customerService;
	
	@Test
	public void testFindAll(){
		customerService.findAllCustomer();
	}
	
	@Test
	public void testSave(){
		Customer c = new Customer();
		c.setCustName("------- ");	
		customerService.saveCustomer(c);
	}
}
2.2 使用xml配置步骤
2.2.1 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">
	<!-- 把资源交给spring来管理 -->
	<bean id="customerDao" class="com.itheima.dao.impl.CustomerDaoImpl"></bean>
	
	<bean id="customerService" class="com.itheima.service.impl.CustomerServiceImpl">
		<property name="customerDao" ref="customerDao"></property>
	</bean>
</beans>
2.2.2 第一步:拷贝整合junit的必备jar包到lib目录

在这里插入图片描述

2.2.3 第二步:使用@RunWith注解替换原有运行器
@RunWith(SpringJUnit4ClassRunner.class)
public class CustomerServiceTest {
	
	private ICustomerService customerService;
	
	@Test
	public void testFindAll(){
		customerService.findAllCustomer();
	}
	
	@Test
	public void testSave(){
		Customer c = new Customer();
		c.setCustName("sssss ");	
		customerService.saveCustomer(c);
	}
}
2.2.4 第三步:使用@ContextConfiguration指定spring配置文件的位置
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:bean.xml"})
public class CustomerServiceTest {

	private ICustomerService customerService;
	
	@Test
	public void testFindAll(){
		customerService.findAllCustomer();
	}
	
	@Test
	public void testSave(){
		Customer c = new Customer();
		c.setCustName("sssss ");	
		customerService.saveCustomer(c);
	}
}
2.2.5 第四步:使用@Autowired给测试类中的变量注入数据
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:bean.xml"})
public class CustomerServiceTest {

	@Autowired
	private ICustomerService customerService;
	
	@Test
	public void testFindAll(){
		customerService.findAllCustomer();
	}
	
	@Test
	public void testSave(){
		Customer c = new Customer();
		c.setCustName("一一一一 ");	
		customerService.saveCustomer(c);
	}
}
2.3 使用纯注解配置步骤
2.3.1 第一步:拷贝整合junit的必备jar包到lib目录

在这里插入图片描述

2.3.2 第二步:把资源都用注解管理
@Service("customerService")
public class CustomerServiceImpl implements ICustomerService {

	@Autowired
	private ICustomerDao customerDao;

	@Override
	public List<Customer> findAllCustomer() {
		return customerDao.findAllCustomer();
	}

	@Override
	public void saveCustomer(Customer customer) {
		customerDao.save(customer);
	}
}

/**
 * 客户的持久层实现类
 */
@Repository("customerDao")
public class CustomerDaoImpl implements ICustomerDao {

	@Override
	public List<Customer> findAllCustomer() {
		System.out.println("查询了所有客户");
		return null;
	}

	@Override
	public void save(Customer customer) {
		System.out.println("保存了客户");
	}
}
2.3.3 第三步:使用注解配置方式创建spring容器

@Configuration
@ComponentScan(basePackages={“com.itheima”})
public class CustomerServiceTest {

@Autowired
private ICustomerService customerService;

@Test
public void testFindAll(){
	customerService.findAllCustomer();
}

@Test
public void testSave(){
	Customer c = new Customer();
	c.setCustName("一一一一 ");	
	customerService.saveCustomer(c);
}

}

2.3.4 第四步:使用RunWith注解和ContextConfiguration注解配置

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={CustomerServiceTest.class})
@Configuration
@ComponentScan(basePackages={“com.itheima”})
public class CustomerServiceTest {

@Autowired
private ICustomerService customerService;

@Test
public void testFindAll(){
	customerService.findAllCustomer();
}

@Test
public void testSave(){
	Customer c = new Customer();
	c.setCustName("一一一一 ");	
	customerService.saveCustomer(c);
}

}

2.4 为什么不把测试类配到xml中

在解释这个问题之前,先解除大家的疑虑,配到XML中能不能用呢?
答案是肯定的,没问题,可以使用。
那么为什么不采用配置到xml中的方式呢?
这个原因是这样的:
第一:当我们在xml中配置了一个bean,spring加载配置文件创建容器时,就会创建对象。
第二:测试类只是我们在测试功能时使用,而在项目中它并不参与程序逻辑,也不会解决需求上的问题,所以创建完了,并没有使用。那么存在容器中就会造成资源的浪费。
所以,基于以上两点,我们不应该把测试配置到xml文件中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从入门小白到小黑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值