1. Spring简介
1.1 Spring是什么
Spring是分层的JavaSE/EE全栈轻量级开源框架,
核心两大模块:IOC、AOP
作用:解耦、简化开发、方便整合其他框架(MyBatis、Redis等)
1.2 Spring框架的优点
- 方便解耦,简化开发,Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理。IOC的作用。
- AOP编程的支持,Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。(可扩展性)
- 声明式事务的支持,只需要通过配置就可以完成对事务的管理,而无需手动编程。
- 方便程序的测试,Spring对Junit4支持,可以通过注解方便的测试Spring程序。
5.方便集成各种优秀框架,Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)的直接支持。
6.降低JavaEE API的使用难度,Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。
1.3 IOC 控制反转 Inversion of Control
- 传统方式:程序员自己new 对象,对象的创建控制权在程序员手里
- IOC:对象的创建、管理、销毁交给Spring容器,控制权反转给框架
- 容器:ApplicationContext(核心容器接口)
- ClassPathXmlApplicationContext:加载类路径下xml
- FileSystemXmlApplicationContext:加载磁盘绝对路径xml
- Bean:Spring容器管理的对象,统称为Bean
- 好处:降低耦合度,不需要自己new对象
1.3 DI 依赖注入 Dependency Injection
DI是IOC的实现手段:容器在创建Bean的时候,自动给Bean里面的成员变量赋值(注入依赖对象)
IOC是思想,DI是实现
2. Bean三种实例化方式
目标:告诉Spring怎么创建Bean对象
1.无参构造实例化(最常用)
<bean id ="us1" class ="com.qcby.service.serviceImpl.UserServiceImpl"></bean>
Spring反射调用目标类无参构造创建对象;必须有无参构造。
2.静态工厂实例化
<bean id ="us2" class ="com.qcby.demo1.StaticFactory" factory-method ="createUs"></bean>
class写工厂类,factory-method 指定静态方法;直接调用静态方法返回Bean,不用创建工厂对象。
package com.qcby.demo1;
import com.qcby.service.UserService ;
import com.qcby.service.serviceImpl.UserServiceImpl;
public class StaticFactory {
public static UserService createUs(){
System.out .println("通过静态工厂的方式创建UserServiceImpl对象...");
return new UserServiceImpl();
}
}
3.实例工厂(动态工厂)
<bean id ="dfactory" class ="com.qcby.demo1.Dfactory" />
<bean id ="us3" factory-bean ="dfactory" factory-method ="createUs" />
先把工厂注册成Bean,factory-bean引用工厂id,调用工厂非静态方法生成目标对象。
package com.qcby.demo1;
import com.qcby.service.UserService ;
import com.qcby.service.serviceImpl.UserServiceImpl;
public class Dfactory {
// 普通成员方法(非 static ),必须先有工厂实例才能调用
public UserService createUs(){
System.out .println("实例化工厂的方式...");
return new UserServiceImpl();
}
}
| 方式 | 是否 static | 特点 |
|---|---|---|
| 无参构造 | - | 日常开发首选 |
| 静态工厂 | ✅ static | 适配第三方静态工厂 |
| 实例工厂 | ❌ 非 static | 工厂有成员属性、状态 |
易错点:工厂内部new目标对象,仍然依赖目标类的无参构造!
3. Spring框架的Bean管理的配置文件方式
id属性,Bean起个名字,在约束中采用ID的约束,唯一,取值要求:必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号 id:不能出现特殊字符。
class属性,Bean对象的全路径。
scope属性,scope属性代表Bean的作用范围。
singleton单例(默认值),最常用的方式。
prototype多例
request应用在Web项目中,每次HTTP请求都会创建一个新的Bean
session应用在Web项目中,同一个HTTP Session 共享一个Bean
Bean对象的创建和销毁的两个属性配置
说明:Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法
init-method,当bean被载入到容器的时候调用init-method属性指定的方法
destroy-method,当bean从容器中删除的时候调用destroy-method属性指定的方法
单例的对象销毁:跟着容器工厂关闭才销毁
多例的对象销毁:垃圾回收机制进行回收的
考点: singleton:容器启动就创建;prototype:调用getBean才创建
4. Bean生命周期 ⭐
完整流程(xml方式)
- 实例化(调用无参构造)
- 属性赋值(DI依赖注入)
- 初始化(init-method 指定初始化方法)
- 对象正常使用
- 销毁(destroy-method 指定销毁方法,容器关闭时执行,单例才会销毁,多例不会由容器销毁)
xml配置:
<bean id="us1" class="xxx" init-method="init" destroy-method="destroy"/>
口诀:构造 → 赋值 → 初始化 → 使用 → 销毁
5. DI依赖注入
给Bean里面成员变量赋值,两种主流方式:set注入、构造注入
前提:类里面要有对应的set方法 / 构造方法
5.1 Set注入(最常用)
package com.qcby.service;
public interface OrderService {
public void saveOrder();
}
package com.qcby.service.serviceImpl;
import com.qcby.dao.OrderDao ;
import com.qcby.service.OrderService ;
public class OrderServiceImpl implements OrderService {
private OrderDao orderDao;
public void setOrderDao(OrderDao orderDao) {
this .orderDao = orderDao;
}
private String msg;
private int age;
public void setMsg(String msg) {
this .msg = msg;
}
public void setAge(int age) {
this .age = age;
}
public void saveOrder() {
System.out .println("业务层:保存订单..."+msg+" - "+age);
orderDao.saveOrder();
}
}
package com.qcby.dao;
public interface OrderDao {
void saveOrder();
}
package com.qcby.dao.daoImpl;
import com.qcby.dao.OrderDao ;
public class OrderDaoImpl implements OrderDao {
public void saveOrder() {
System.out .println("持久层:保存订单...");
}
}
<!--DI :依赖注入 -->
<bean id ="os" class ="com.qcby.service.serviceImpl.OrderServiceImpl">
<!-- 引用类型, ref 指向另一个 bean 的 id od --> <property name ="orderDao" ref ="od" />
<!-- 简单类型, value 赋值 --> <property name ="msg" value ="你好" />
<property name ="age" value ="30" />
</bean>
<!-- dao 层 bean , id=od -->
<bean id ="od" class ="com.qcby.dao.daoImpl.OrderDaoImpl"></bean>
5.2 构造注入(带参数构造)
package com.qcby.demo2;
public class Car {
// 名称
private String cname;
// 金额
private Double money;
publicCar() {
}
// 带参数构造方法
public Car(String cname, Double money) {
this .cname = cname;
this .money = money;
}
@Override
publicString toString() {
return "Car{" +
"cname='" + cname + '\'' +
", money=" + money +
'}';
}
}
<bean id ="car" class ="com.qcby.demo2.Car">
<constructor-arg name ="cname" value ="大奔" />
<constructor-arg name ="money" value ="400000" />
</bean>
5.3. 数组,集合(List,Set,Map),Properties等的注入
package com.qcby.demo3;
import java.util.Arrays;
import java.util.List ;
import java.util.Map ;
import java.util.Properties;
public class CollectionBean {
// 1. 字符串数组
private String \[\] strs;
public void setStrs(String\[\] strs) {
this .strs = strs;
}
// 2.List 集合
private List <String> list;
public void setList(List <String> list) {
this .list = list;
}
// 3.Map 集合(键值对)
private Map <String,String> map;
public void setMap(Map <String, String> map) {
this .map = map;
}
// 4.Properties ,专门存字符串格式的配置(比如账号密码)
private Properties properties;
public void setProperties(Properties properties) {
this .properties = properties;
}
// toString :打印对象的时候,直接看到里面集合内容,方便测试
@Override
publicString toString() {
return "CollectionBean{" +
"strs=" + Arrays.toString (strs) +
", list=" + list +
", map=" + map +
", properties=" + properties +
'}';
}
}
<bean id ="collectionBean" class ="com.qcby.demo3.CollectionBean">
<!-- 给数组 strs 赋值 --> <property name ="strs">
<array>
<value>美美</value>
<value>小凤</value>
</array>
</property>
<!-- 给 list 赋值 --> <property name ="list">
<list>
<value>熊大</value>
<value>熊二</value>
</list>
</property>
<!-- 给 map 赋值, entry 就是一条键值对 --> <property name ="map">
<map>
<entry key ="aaa" value ="老王"/>
<entry key ="bbb" value ="小王"/>
</map>
</property>
<!-- Properties 配置 --> <property name ="properties">
<props>
<prop key ="username">root</prop>
<prop key ="password">123456</prop>
</props>
</property>
</bean>
5.4. 多配置文件方式
在src的目录下又多创建了一个配置文件,现在是两个核心的配置文件,那么加载这两个配置文件的方式有两种!
主配置文件中包含其他的配置文件:
<import resource="applicationContext2.xml"/>
工厂创建的时候直接加载多个配置文件:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml","applicationContext2.xml");
**6.**Spring框架开发程序的方式
6.1 Spring框架开发方式
-
需求:编写service和dao的类,演示代码
-
技术选择:持久层使用原始的JDBC的程序,连接池选择的是Druid连接池。创建maven工程,导入开发的jar包
-
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qcby</groupId>
<artifactId>springdemo</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>springdemo Maven Webapp</name>
<url>http://maven.apache.org</url><dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!-- 连接池 --> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<!-- mysql 驱动 --> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties><build>
<finalName>springdemo</finalName>
</build>
</project>
创建数据库,创建表结构
create database spring_db;
use spring_db;
create table account(
id int primary key auto_increment,
name varchar(40),
money double
)character set utf8 collate utf8_general_ci;
insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);
编写JavaBean的类
packagecom.qcby.entity;
importjava.io.Serializable;
public classAccount implementsSerializable{
private static final long*serialVersionUID*= 7355810572012650248L;
privateInteger id;
privateString name;
privateDouble money;
publicInteger getId() {
returnid;
}
public voidsetId(Integer id) {
this.id = id;
}
publicString getName() {
returnname;
}
public voidsetName(String name) {
this.name = name;
}
publicDouble getMoney() {
returnmoney;
}
public voidsetMoney(Double money) {
this.money = money;
}
@Override
publicString toString() {
return"Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
编写AccountDao的接口和实现类
packagecom.qcby.dao;
public interfaceOrderDao{
voidsaveOrder();
}
packagecom.qcby.dao.daoImpl;
importcom.qcby.dao.OrderDao;
public classOrderDaoImpl implementsOrderDao{
public voidsaveOrder() {
System.*out*.println("持久层:保存订单...");
}
}
packagecom.qcby.service;
importcom.qcby.entity.Account;
importjava.util.List;
public interfaceAccountService{
publicList<Account> findAll();
}
packagecom.qcby.service.serviceImpl;
importcom.qcby.dao.AccountDao;
importcom.qcby.entity.Account;
importcom.qcby.service.AccountService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Component;
importjava.sql.Connection;
importjava.sql.PreparedStatement;
importjava.sql.ResultSet;
importjava.util.ArrayList;
importjava.util.List;
@Component("accountService")
public classAccountServiceImpl implementsAccountService{
//依赖注入
privateAccountDaoaccountDao;
public voidsetAccountDao(AccountDaoaccountDao) {
this.accountDao = accountDao;
}
/\*\* \*查询所有的数据
\**@return*\*/publicList<Account> findAll() {
returnaccountDao.findAll();
}
}
编写配置文件
<?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 https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///spring_db?useSSL=false&serverTimezone=Asia/Shanghai" />
<property name="username" value="root" />
<property name="password" value="980802" />
</bean>
<bean id="accountDao" class="com.qcby.dao.daoImpl.AccountDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="accountService" class="com.qcby.service.serviceImpl.AccountServiceImpl">
<property name="accountDao" ref="accountDao" />
</bean>
</beans>
编程测试程序
@Test
public voidrun3(){
ApplicationContextac=newClassPathXmlApplicationContext("applicationContext.xml");
AccountServiceaccountService = (AccountService) ac.getBean("accountService");
List<Account> list = accountService.findAll();
for(Account account : list) {
System.*out*.println(account);
}
}
7. IOC注解的方式
7.1. IOC注解方式的快速入门
IOC注解的方式依赖没有变化
编写接口和实现类
package com.qcby.service;
public interface UserService {
public void hello();
}
package com.qcby.service.serviceImpl;
import com.qcby.service.UserService ;
importorg.springframework.stereotype.Component;
//相当于<bean id="us"class="com.qcby.service.serviceImpl.UserServiceImpl" />
@Component(value = "us")
public class UserServiceImpl implements UserService {
@Override
public void hello() {
System.out .println("Hello IOC注解...");
}
}
编写配置文件,重点是开启注解扫描。
<?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/context/spring-context.xsd">
<!-- 扫描com.qcby下所有子包
entity实体类一般不加@Component,不需要交给Spring管理 -->
<context:component-scan base-package="com.qcby" />
</beans>
编写测试方法
@Test
public void run2(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService ) ac.getBean("us");
userService.hello();
}
7.2常用的注解
bean管理类常用的4个注解(作用相同,推荐使用在不同分层上)
**@Component** 普通的类
@Controller 表现层
@Service 业务层
**@Repository** 持久层
依赖注入常用的注解
**@Value** 用于注入普通类型(String,int,double等类型)
**@Autowired** 默认按类型进行自动装配(引用类型)
@Qualifier 和**@Autowired**一起使用,强制使用名称注入
@ResourceJava提供的注解,也被支持。使用name属性,按名称注入
对象生命周期(作用范围)注解
@Scope 生命周期注解,取值singleton(默认值,单实例)和prototype(多例)
初始化方法和销毁方法注解(了解)
**@PostConstruct** 相当于init-method
@PreDestroy 相当于destroy-method
单例的销毁时机是跟随容器的 容器销毁对象销毁
多例的销毁时机是java的垃圾回收机制控制的
@Service("userService") //括号内就是bean的id,不写默认首字母小写类名
public class UserServiceImpl implements UserService{}
7.3 IOC纯注解的方式
纯注解的方式是微服务架构开发的主要方式,所以也是非常的重要。纯注解的目的是替换掉所有的配置文件。但是需要编写配置类。
编写配置类,替换掉applicationContext.xml配置文件
package com.qcby.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource ;
/**
* Spring**注解配置类,替代传统的 spring.xml 配置文件
*/
@Configuration *//*标识当前类是 Spring 的配置类
@ComponentScan("com.qcby") *//*组件扫描:扫描 com.qcby 包及其子包下带 @Component 等注解的类,交给 IOC 容器管理
public class SpringConfig {
/**
*注册 Druid 数据源 Bean ,交给 Spring IOC 容器
* @return 数据源对象
*/ @Bean("dataSource") //将方法返回对象存入 IOC 容器, bean 名称为 dataSource
public DataSource createDataSource() {
*//创建 Druid 连接池对象
DruidDataSource dataSource = new DruidDataSource();
//设置 mysql 驱动类( mysql8 使用 cj 包下的驱动)
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
// url:连接数据库地址
// spring_db :数据库名; serverTimezone 时区; useSSL 关闭 ssl ; allowPublicKeyRetrieval 解决公钥报错
dataSource.setUrl("jdbc:mysql:///spring_db?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true");
*// mysql用户名
dataSource.setUsername("root");
*// mysql*密码
dataSource.setPassword("980802");
return dataSource;
}
}
测试方法的编写
@Test
public void run3(){
ApplicationContext ac=new AnnotationConfigApplicationContext(SpringConfig.class );
AccountService accountService = (AccountService ) ac.getBean("accountService");
List <Account> list = accountService.findAll();
for (Account account : list) {
System.out .println(account);
}
}
常用的注解总结
@Configuration 声明是配置类
@ComponentScan 扫描具体包结构的
@Import注解 Spring的配置文件可以分成多个配置的,编写多个配置类。用于导入其他配置类
package com.qcbyjy.demo4;
import org.springframework.context.annotation.Configuration;
/**
* 新的配置类
*
*/
@Configuration // 声明配置类
public class SpringConfig2 {
}
// 声明当前类是配置类
@Configuration
// 扫描指定的包结构
@ComponentScan(value = "com.qcbyjy.demo4")
// @ComponentScan(value = {"com.qcbyjy.demo4","com.qcbyjy.demo3"})
// 引入新的配置类
@Import(value = {SpringConfig2.class})
public class SpringConfig {
@Bean注解 只能写在方法上,表明使用此方法创建一个对象,对象创建完成保存到IOC容器中
package com.qcbyjy.demo4;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import javax.sql.DataSource;
/**
*
* Spring的配置类,替换掉applicationContext.xml
*
*/
// 声明当前类是配置类
@Configuration
// 扫描指定的包结构
@ComponentScan(value = "com.qcbyjy.demo4")
// @ComponentScan(value = {"com.qcbyjy.demo4","com.qcbyjy.demo3"})
// 引入新的配置类
@Import(value = {SpringConfig2.class})
public class SpringConfig {
/**
* 创建连接池对象,返回对象,把该方法创建后的对象存入到连接池中,使用@Bean注解解决
<!--配置连接池对象-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///spring_db" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
*
* @return
*/
@Bean(name="dataSource")
public DataSource createDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring_db");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
}
8. Spring框架整合JUnit单元测试
8.1 Spring框架整合JUnit单元测试
每次进行单元测试的时候,都需要编写创建工厂,加载配置文件等代码,比较繁琐。Spring提供了整合Junit单元测试的技术,可以简化测试开发。
必须先有Junit单元测试的环境,也就是说已经导入Junit单元测试的jar包。再导入spring-test的坐标依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
<scope>test</scope>
</dependency>
编写类和方法,把该类交给IOC容器进行管理
package com.qcbyjy.demo5;
public class User {
public void sayHello(){
System.out.println("Hello....");
}
}
编写配置文件applicationContext_test.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="user" class="com.qcbyjy.demo5.User"/>
</beans>
编写测试代码
package com.qcbyjy.test;
import com.qcbyjy.demo5.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Spring整合Junit单元测试
*
*/
@RunWith(value = SpringJUnit4ClassRunner.class) // 运行单元测试
@ContextConfiguration(value = "classpath:applicationContext_test.xml") // 加载类路径下的配置文件
public class Demo5 {
// 测试哪一个对象,把该对象注入进来,在测试环境下,可以使用注解的方式注入测试的对象
// 按类型自动注入
@Autowired
private User user;
@Test
public void run1(){
// 创建工厂,加载配置文件......
// 调用对象的方法
user.sayHello();
}
}
8.2 Spring整合单元测试(纯注解方式)
编写类和方法
package com.qcbyjy.demo6;
import org.springframework.stereotype.Component;
@Component
public class Customer {
public void save(){
System.out.println("保存客户...");
}
}
编写配置类
package com.qcbyjy.demo6;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* Spring整合Junit配置类
*/
// 声明
@Configuration
// 扫描包结构
@ComponentScan(value = "com.qcbyjy.demo6")
public class SpringConfig6 {
}
编写测试方法
package com.qcbyjy.test;
import com.qcbyjy.demo6.Customer;
import com.qcbyjy.demo6.SpringConfig6;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Spring整合Junit 注解的方式测试
*/
@RunWith(SpringJUnit4ClassRunner.class)
// 加载配置类
@ContextConfiguration(classes = SpringConfig6.class)
public class Demo6 {
// 按类型注入
@Autowired
private Customer customer;
/**
* 测试
*/
@Test
public void run1(){
customer.save();
}
}