Spring第一天
- Spring概述
1.1程序的耦合和解耦
-
-
- 什么是程序的耦合
-
我们在开发中,会写很多的类,而有些类之间不可避免的产生依赖关系,这种依赖关系称之为耦合。有些依赖关系是必须的,有些依赖关系可以通过优化代码来解除的。请看下面的示例代码:
/** * 客户的业务层实现类依赖customerDao类,这两个类就称为耦合 */ public class CustomerServiceImpl implements ICustomerService { private ICustomerDao customerDao = new CustomerDaoImpl(); } |
上面的代码表示:业务层调用持久层,并且此时业务层在依赖持久层的接口和实现类。如果此时没有持久层实现类,编译将不能通过。这种依赖关系就是我们可以通过优化代码解决的。
再比如:
下面的代码中,我们的类依赖了 MySQL 的具体驱动类,如果这时候更换了数据库品牌,我们需要改源码来修改数据库驱动。这显然不是我们想要的。
public class JdbcDemo1 { /** * JDBC 操作数据库的基本入门中存在什么问题? * 导致驱动注册两次是个问题,但不是严重的。 * 严重的问题:是当前类和 mysql 的驱动类有很强的依赖关系。 * 当我们没有驱动类的时候,连编译都不让。 * 那这种依赖关系,就叫做程序的耦合 * * 我们在开发中,理想的状态应该是: * 我们应该尽力达到的:编译时不依赖,运行时才依赖。 */ 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.遍历结果集 } |
-
-
- 解决程序耦合的思路
-
当是我们讲解 jdbc 时,是通过反射来注册驱动的,代码如下:
Class.forName("com.mysql.jdbc.Driver");
这时的好处是,我们的类中不再依赖具体的驱动类,此时就算删除 mysql 的驱动 jar 包,依然可以编译。但是因为没有驱动类,所以不能运行。
不过,此处也有个问题,就是我们反射类对象的全限定类名字符串是在 java 类中写死的,一旦要改还是要修改源码。
解决这个问题也很简单,使用配置文件配置。
-
-
- 工厂模式解耦
-
在实际开发中我们可以把所有的 dao mapper 和 service 和 action web controller对象使用配置文件配置起来,当启动服务器应用加载的时候,通过读取配置文件,把这些对象创建出来 并存起来。在接下来的使用的时候,直接拿过来用就好了。
1.1.4 控制反转-Inversion Of Control
1 、存哪去?
分析:由于我们是很多对象,肯定要找个集合来存。这时候有 Map 和 List 供选择。
到底选 Map 还是 List 就看我们有没有查找需求。有查找需求,选 Map。
所以我们的答案就是
在应用加载时,创建一个 Map,用于存放 action,Service 和 dao 对象。
我们把这个 map 称之为 容器。
2、还是没解释什么是工厂?
工厂就是负责给我们从容器中获取指定对象的类。这时候我们获取对象的方式发生了改变。
原来:
我们在获取对象时,都是采用 new 的方式。是主动的。
现在:
我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象。是被动的。
这种被动接收的方式获取对象的思想就是控制反转,它是 spring 框架的核心之一。
它的作用只有一个:削减计算机程序的耦合。
-
- Spring介绍
- Spring 概述
- Spring介绍
Spring框架有两大核心 分别是IOC(控制反转)和AOP(面向切面编程)
1.2.1.1 Spring简介
Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:
反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 SpringMVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架。
1.2.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 雏形)
-
-
- Spring的优势
-
方便解耦,简化开发
通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
AOP 编程的支持
通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。
声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。
方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。
方便集成各种优秀框架
Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz 任务调度框架 等)的直接支持。低 降低 JavaEE API 的使用难度Spring 对 JavaEE API(如 JDBC、JavaMail、远程调用 CXF 等)进行了薄薄的封装层,使这些 API 的使用难度大为降低。
Java 源码是经典学习范例
Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以及对 Java 技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例。
-
-
- Spring的体系结构
-
-
-
- Spring开发包
-
官网:http://spring.io/
下载地址:
http://repo.springsource.org/libs-release-local/org/springframework/spring
解压:(Spring 目录结构:)
* docs :API 和开发规范.
* libs :jar 包和源码.
* schema :约束.
我们上课使用的版本是Spring 4.2.4
- 使用Spring的IOC解决程序耦合
2.1案例的前期准备
本章我们使用的案例是,客户的业务层和持久层的依赖关系解决。在开始 spring 的配置之前,我们要先准备一下环境。由于我们是使用 spring 解决依赖关系,并不是真正的要做增删改查操作,所以此时我们没必要写实体类。并且我们在此处使用的是 java 工程,不是 java web 工程。
2.1.1 创建业务层接口和实现类
客户接口: CustomerService
/** * 客户的业务层接口 */ public interface ICustomerService { /** * 保存客户 * @param customer */ void saveCustomer(); } |
客户的实现类 CustomerServiceImpl:
/** * 客户的业务层实现类 */ public class CustomerServiceImpl implements ICustomerService { private ICustomerDao customerDao = new CustomerDaoImpl();// 此处有依赖关系 @Override public void saveCustomer() { customerDao.saveCustomer(); } } |
2.1.2 创建持久层接口和实现类
客户的持久层接口:
public interface ICustomerDao { /** * 保存客户 */ void saveCustomer(); }
|
客户的持久层实现类:
public class CustomerDaoImpl implements ICustomerDao { @Override public void saveCustomer() { System.out.println("保存了客户"); } }
|
2.2 基于XML的配置
2.2.1 环境搭建
2.2.1.1 第一步: 拷贝必备的jar包到工程的lib目录
2.2.1.2 第二步:在类的根路径下创建一个任意名称的 xml 文件 (不能是中文)
给配置文件导入约束:
<?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: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> |
2.2.1.3 第三步:把资源交给 spring 来管理置 ,在配置文件中配置 service 和 dao
<!-- 把资源交给 spring 来管理 --> <bean id="customerDao" class="com.bdqn.dao.impl.CustomerDaoImpl"/> <bean id="customerService" class="com.bdqn.service.impl.CustomerServiceImpl"/> |
2.2.2 测试环境是否成功
2.2.2.1 获取 spring 容器
/** * 模拟一个表现层 */ public class Client { /** * 获取 spring 的容器,以及从容器中获取 bean 对象 * * ApplicationContext * 它是一个接口,有两个实现类。 * 分别是: * ClassPathXmlApplicationContext: * 它永远都是从类的根路径下加载配置文件 推荐使用这种 * FileSystemXmlApplicationContext: * 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。 */ public static void main(String[] args) { //1.使用 ApplicationContext 接口,就是在获取 spring 容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根据 bean 的 id 获取对象 ICustomerService customerService = (ICustomerService) ac.getBean("customerService"); System.out.println(customerService); ICustomerDao customerDao = (ICustomerDao) ac.getBean("customerDao"); System.out.println(customerDao); } } 问题:由于对象都交给 spring 管理了,这时如果我们把 service 实现了的这行代码: private ICustomerDao customerDao = new CustomerDaoImpl();// 此处有依赖关系 改为 private ICustomerDao customerDao = null; 使用 service 对象调用 saveCustomer 方法会出现什么问题呢? 运行结果: 空指针异常。 原因是 customerDao 对象没有赋值。 如果在程序运行期间,spring 框架能帮我们给 customerDao 对象赋了值,那该多好。 带着脑海里的这个想法,继续往下看。 |
2.2.2.2 Spring工厂类结构
BeanFactory 才是 Spring 容器中的顶层接口。ApplicationContext 是它的子接口。
BeanFactory 和 ApplicationContext 的区别:创建对象的时间点不一样。
ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
BeanFactory:什么时候对象使用什么时候创建对象。
2.2.3 IOC 中 中 bean 标签 和 管理对象细节
2.2.3.1 bean 标签
作用:
用于配置对象让 spring 来创建的。
默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
属性:
id :给对象在容器中提供一个唯一标识。用于获取对象。
class :指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
scope :指定对象的作用范围。
* singleton :默认值,单例的.
* prototype :多例的.
* request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
* session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
init-method :指定类中的初始化方法名称。
destroy-method :指定类中销毁方法名称。
2.2.3.2 bean 的作用范围和生命周期
单例对象: scope="singleton"
一个应用只有一个对象的实例。它的作用范围就是整个引用。
生命周期:
对象出生:当应用加载,创建容器时,对象就被创建了。
对象活着:只要容器在,对象一直活着。
对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
多例对象: scope="prototype"
每次访问对象时,都会重新创建对象实例。
生命周期:
对象出生:当使用对象时,创建新的对象实例。
对象活着:只要对象在使用中,就一直活着。
对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。
2.2.4 spring 的依赖注入
2.2.4.1 依赖注入的概念
它是 spring 框架核心 ioc 的具体实现方式。简单的说,就是坐等框架把对象传入,而不用我们自己去获取.
2.2.4.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.bdqn.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> |
2.2.4.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.bdqn.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.2.4.4 注入集合属性
顾名思义,就是给类中的集合成员传值,它用的也是 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.bdqn.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> |
第3 章 附录
3.1 Spring 配置文件中提示的配置
3.1.1 复制路径:
http://www.springframework.org/schema/beans/spring-beans.xsd
3.1.2 查找 XML Catalog:
Spring 第 二 天
第1 章 基于注解的 IOC 配置
1.1 写在最前
学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样的,都是要降低程序间的耦合。只是配置的形式不一样。关于实际的开发中到底使用 xml 还是注解,每家公司有着不同的使用习惯。所以这两种配置方式我们都需要掌握。
1.2 环境搭建
1.2.1 第一步:拷贝必备 jar 包到工程的 lib 目录。
注意:在基于注解的配置中,我们还要多拷贝一个 aop 的 jar 包。如下图:
1.2.2 第二步:在类的根路径下创建一个任意名称的 xml 文件 (不能是中文)
基于注解整合时,导入约束时需要多导入一个 context 名称空间下的约束.
给配置文件导入 context 约束:
<?xml version="1.0" encoding="UTF-8"?> <?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: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/beans/spring-context.xsd">
</beans> |
1.2.3 使用@Component 注解配置管理的资源
@Component(value="customerServie") public class CustomerServiceImpl implements CustomerService { @Override public void saveCustomer(Customer customer) { System.out.println("执行了保存客户!"); } } |
1.2.4 第四步在 spring 的配置文件中开启 spring 对注解 ioc 的支持
<!-- 告知spring框架在,读取配置文件,创建容器时,扫描注解,依据注解创建对象,并存入容器中 --> <context:component-scan base-package="com.bdqn"></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
1.3.4 和生命周期相关的:( 了解)
相当于:<bean id="" class="" init-method="" destroy-method="" />
1.3.4.1 @PostConstruct
作用:
用于指定初始化方法。
1.3.4.2 @PreDestroy
作用:
用于指定销毁方法。
1.3.5 关于注解和 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="cn.bdqn"></context:component-scan>
如果他要也能用注解配置,那么我们就可以脱离 xml 文件了。
1.5.2 使用注解配置要扫描的包
项目结构图:
在此图中,我们已经一点也看不到 xml 的身影了。那么,那句关键的配置跑哪去了呢?
在一个新的类上:用这个类代替配置文件.
配置类代码:
@Configuration //标明该类是一个配置类 @ComponentScan(basePackages= {"com.bdqn"})//配置扫描的包 public class SpringConfiguration { } |
测试类代码:
@Test public void testConfig() { //1.获取容器:由于我们已经没有了 xml 文件,所以再用读取 xml 方式就不能用了。 //这时需要指定加载哪个类上的注解 ApplicationContext aContext=new AnnotationConfigApplicationContext(SpringConfiguration.class); //从容器中获得对象 CustomerService customerService = (CustomerService) aContext.getBean("customerServie"); Customer customer=new Customer(); customer.setCustName("李斯"); customer.setCustSource("互联网"); //调用对象的保存用户的方法 customerService.saveCustomer(customer); } |
1.5.3 新注解说明
1.5.3.1 @Configuration
作用:
用于指定当前类是一个配置类,会从该类上加载注解。读取该类上@ ComponentScan 注解
初始化 spring 容器。
1.5.3.2 @ComponentScan
作用:
用于指定 spring 在初始化容器时要扫描的包。
属性:
basePackages :用于指定要扫描的包。和该注解中的 value 属性作用一样。
1.5.3.3 @Bean
作用:把方法的返回值放入到Spring容器中
该注解只能写在方法上,表明使用此方法创建一个对象,并且交给 spring 管理。
属性:name :给当前@Bean 注解的方法创建的对象指定一个名称(即 bean 的 id)。
配置类代码:
@Component public class JdbcConfig { /** 把方法的返回值放入Spring容器 name属性用于指定对象的名字 相当于 <bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource"></bean> */ @Bean(name="ds") public DataSource getDs() throws Exception { //创建一个数据源 ComboPooledDataSource dataSource=new ComboPooledDataSource(); //设置数据源连接数据库的四要素 dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mydb"); dataSource.setUser("root"); dataSource.setPassword("root"); //返回数据源 return dataSource; } } |
测试代码:
@Test public void testBean() { //根据配置类获得容器 ApplicationContext aContext=new AnnotationConfigApplicationContext(SpringConfiguration.class); //从容器中获得数据源 DataSource dSource=(DataSource) aContext.getBean("ds"); //创建QueryRunner对象 QueryRunner runner=new QueryRunner(dSource); //实行插入数据语句 try { runner.update("insert into account (username,money) values('Monica',500000)"); } catch (SQLException e) { e.printStackTrace(); } } |
1.5.3.4 @Import
作用:
用于导入其他配置类
属性:
value[] :用于指定其他配置类的字节码。
示例代码:这样就不需要再向容器中放入JdbcConfig类,@Component注解省略
直接使用@Important注解加载配置类
@Configuration //标明该类是一个配置类 @ComponentScan("com.bdqn")//配置扫描的包 @Import(JdbcConfig.class)//用于导入其它配置类 public class SpringConfiguration { } |
1.5.3.5 @PropertySource
作用:用于加载.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="ds") public DataSource getDs() throws Exception { //创建一个数据源 ComboPooledDataSource dataSource=new ComboPooledDataSource(); //设置数据源连接数据库的四要素 dataSource.setDriverClass(driver); dataSource.setJdbcUrl(url); dataSource.setUser(username); dataSource.setPassword(password); //返回数据源 return dataSource; } |
注意4.3以前版本需要提供占位符类:
我们目前上课使用的版本是 4.2.4,在 在 spring4.3 以前都需要提供一个占位符配置器: PropertySourcesPlaceholderConfigurer 在 而在 spring4.3 以后,则不需要提供。 提供 的方式如下:(在 在 SpringConfiguration 或 JdbcConfig 中 配置均可 ) 4.2版本的配置 @Configuration //标明该类是一个配置类 @ComponentScan("com.bdqn")//配置扫描的包 @Import(JdbcConfig.class)//用于导入其它配置类 @PropertySource("classpath:/com/bdqn/config/jdbc.properties") //导入properties配置文件 value属性用于指定配置文件的位置 public class SpringConfiguration { @Bean(name="pspc") public static PropertySourcesPlaceholderConfigurer createPSPC() { return new PropertySourcesPlaceholderConfigurer(); } } |
1.5.3.6 @Qualifier的第二种使用方法
1.第一种方式 和@Autowire一起配合起来使用,用于指定固定一个对象的配置.
2.用于向方法参数注入Spring容器中对象.
示例代码:
@Bean(name="ds") public DataSource getDs() throws Exception { //创建一个数据源 ComboPooledDataSource dataSource=new ComboPooledDataSource(); //设置数据源连接数据库的四要素 dataSource.setDriverClass(driver); dataSource.setJdbcUrl(url); dataSource.setUser(username); dataSource.setPassword(password); //返回数据源 return dataSource; } /** * @Qualifier("ds") 直接使用容器中的ds 向形参赋值 */ @Bean(name="qr") public QueryRunner getRunner(@Qualifier("ds")DataSource ds) { return new QueryRunner(ds); } |
测试代码:
@Test public void testBean() { //根据配置类获得容器 ApplicationContext aContext=new AnnotationConfigApplicationContext(SpringConfiguration.class); //创建QueryRunner对象 QueryRunner runner=(QueryRunner) aContext.getBean("qr"); //实行插入数据语句 try { runner.update("insert into account (username,money) values('runner',100)"); } catch (SQLException e) { e.printStackTrace(); } } |
第2章Spring整合Junit
2.1 准备测试环境
2.1.1 创建业务层接口和实现类
业务层接口:
public interface CustomerService { //保存用户的方法 public void saveCustomer(Customer customer); //查询所有用户方法 public List<Customer> getCustomers(); } |
业务层实现类:
@Component("customerServie") public class CustomerServiceImpl implements CustomerService { private CustomerDao customerDao; //提供set方法用于注入customerDao对象 @Override public void saveCustomer(Customer customer) { customerDao.saveCustomer(customer); } public void setCustomerDao(CustomerDao customerDao) { this.customerDao = customerDao; } @Override public List<Customer> getCustomers() { return customerDao.getCustomers(); } } |
2.1.2 创建持久层接口和实现类
持久层接口:
public interface CustomerDao { //保存用户的方法 public void saveCustomer(Customer customer); //查询所有用户方法 public List<Customer> getCustomers(); } |
持久层实现类:
@Repository public class CustomerDaoImpl implements CustomerDao { @Override public void saveCustomer(Customer customer) { System.out.println("保存了用户1111:"+customer); } @Override public List<Customer> getCustomers() { System.out.println("查询所用的客户!"); return null; } } |
2.1.3 导入 junit 的 的 jar
2.1.4 编写测试类
public class CustomrServiceTest { //创建CustomerService类 private CustomerService customerService; @Test public void saveCustomer() { Customer customer=new Customer(); customer.setCustName("阳江"); customer.setCustSource("旅游海滨"); customerService.saveCustomer(customer); } @Test public void findAllCustomer() { customerService.getCustomers(); } } |
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"> <bean id="service" class="com.bdqn.service.impl.CustomerServiceImpl"> <property name="customerDao" ref="dao"></property> </bean> <bean id="dao" class="com.bdqn.dao.impl.CustomerDaoImpl"></bean> </beans> |
2.2.2 第一步:拷贝整合 junit 的必备 jar 包到 lib
此处需要注意的是,导入 jar 包时,需要导入一个 spring 中 aop 的 jar 包
2.2.3 第二步:使用@RunWith注解替换原有运行器(junit运行器)
//使用RunWith注解替换Spring的运行器 @RunWith(SpringJUnit4ClassRunner.class) public class CustomrServiceTest { //创建CustomerService类 private CustomerService customerService; @Test public void saveCustomer() { Customer customer=new Customer(); customer.setCustName("阳江"); customer.setCustSource("旅游海滨"); customerService.saveCustomer(customer); } @Test public void findAllCustomer() { customerService.getCustomers(); } } |
2.2.4 第三步:使用@ContextConfiguration 指定 spring 配置文件的位置
//使用RunWith注解替换Spring的运行器 @RunWith(SpringJUnit4ClassRunner.class) // @ContextConfiguration 用于指定配置文件的位置 @ContextConfiguration(locations="classpath:applicationContext.xml") public class CustomrServiceTest { //创建CustomerService类 private CustomerService customerService; @Test public void saveCustomer() { Customer customer=new Customer(); customer.setCustName("阳江"); customer.setCustSource("旅游海滨"); customerService.saveCustomer(customer); } @Test public void findAllCustomer() { customerService.getCustomers(); } } |
2.2.5 第四步使用@Autowired 给测试类中的变量注入数据
//使用RunWith注解替换Spring的运行器 @RunWith(SpringJUnit4ClassRunner.class) // @ContextConfiguration 用于指定配置文件的位置 @ContextConfiguration(locations="classpath:applicationContext.xml") public class CustomrServiceTest { //创建CustomerService类 @Autowired private CustomerService customerService; @Test public void saveCustomer() { Customer customer=new Customer(); customer.setCustName("阳江"); customer.setCustSource("旅游海滨"); customerService.saveCustomer(customer); } @Test public void findAllCustomer() { customerService.getCustomers(); } } |
2.3 使用纯注解配置步骤
2.3.1 第一步:拷贝整合 junit的必备 jar 包到 lib 目录
此处需要注意的是,导入 jar 包时,需要导入一个 spring 中 aop 的 jar 包。
2.3.2 第二步 把资源都用注解管理
2.3.3 第三步:使用注解配置方式创建 spring
2.3.4 第四步:使用 RunWith 注解和 ContextConfiguration 注解配置
最终代码:
@Configuration @ComponentScan("com.bdqn") //使用RunWith注解替换Spring的运行器 @RunWith(SpringJUnit4ClassRunner.class) // @ContextConfiguration 用于指定配置文件的位置 @ContextConfiguration(classes=CustomrServiceTest.class) public class CustomrServiceTest { //创建CustomerService类 @Autowired private CustomerService customerService; @Test public void saveCustomer() { Customer customer=new Customer(); customer.setCustName("阳江"); customer.setCustSource("旅游海滨"); customerService.saveCustomer(customer); } @Test public void findAllCustomer() { customerService.getCustomers(); } } |
2.4 为什么 不把测试类配到 xml
在解释这个问题之前,先解除大家的疑虑,配到 XML 中能不能用呢?
答案是肯定的,没问题,可以使用。
那么为什么不采用配置到 xml 中的方式呢?
这个原因是这样的:
第一:当我们在 xml 中配置了一个 bean,spring 加载配置文件创建容器时,就会创建对象。
第二:测试类只是我们在测试功能时使用,而在项目中它并不参与程序逻辑,也不会解决需求上的问题,所以创建完了,并没有使用。那么存在容器中就会造成资源的浪费。
所以,基于以上两点,我们不应该把测试配置到 xml 文件中。
总结:
今天的注解:
创建对象的注解:
@Component
@Controller(用于web层)
@Service(用于service)
@Repository(用于dao)
主配置文件包扫描:
<context:component-scan base-package="com.bdqn"></context:component-scan>
作用范围:
@Scope : singleton、prototype
依赖注入:
@Autowired(自动按照类型注入)
@Qualifier(和@Autowired配合使用用于指定具体类型 value属性指定)
@Resource:jdk name属性 用于指定具体类型
如果只有一个实现类: autowire和resource注解可以互换
@Value
新注解:
@Configuration
@ComponentScan
@Bean name属性
@Import
@PropertySource