spring第二版

    科技2024-09-25  17

    什么是spring

    spring优点

    方便解耦,简化开发,spring就是以大工厂aop编程支持声明事务支持方便测试方便集成各种框架降低javaeeAPi的使用难度

    spring解构

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MLZGBan8-1602062689251)(.\spring.assets\image-20200902210435932.png)]

    入门案例IOC

    先创建一个maven项目

    导入对应的maven依赖

    <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.3.7.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> 对应上面那张图可以看看

    检查是否导入了jar包

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wQ3Iqo7f-1602062689254)(.\spring.assets\image-20200902213928526.png)]

    目标类

    提供UserService接口和实现类

    获得UserService实现类的实例

    之前开发中,直接new一个对象即可,学习spring之后,将由spring创建对象实例->IOC控制反转,之后需要实例对象时,从spring工厂(容器)中获得,需要将实现类的全限定类的全限定名称配置到xml文件中,至于为什么你想想反射

    public interface UserService { void addUser(); } public class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("add user "); } }

    配置文件

    位置:任意,开发中一般在classpath下(src)

    名称:任意位置,开发中常用applicationContext

    内容:添加schema约束

    @Test public void demo01(){ UserService userService=new UserServiceImpl(); userService.addUser(); } @Test public void demo02(){ String xmlPath= "applicationContext.xml"; ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath); //获得内容不需要自己new都是从spring容器获取 UserService userService1= (UserService) applicationContext.getBean("userService"); userService1.addUser(); }

    入门案例DI

    依赖注入

    is a : 是一个 继承

    has a:有一个,成员变量,依赖

    ​ class B{

    ​ private A a; //B类依赖A类

    ​ }

    依赖:一个对象需要使用另一个对象

    注入:通过set方法进行另一个对象实例的设置

    例如: class BookService{

    ​ //之前开发: 接口=实现类(service和dao耦合)

    ​ private BookDao booDao=new BookDaoImpl();

    ​ //spring之后(解耦:service实现类使用dao的接口,不知道具体实现类我可以换)

    ​ private BookDao bookDao;

    ​ setter方法

    }

    模拟spring执行过程

    创建service实例: BookService bookService=new BookServiceImpl(); —>IOC

    创建dao实例:BookDao bookDao=new BookDaoImpl(); ---->IOC

    将dao设置给service bookService.setBookDao(bookDao)---->DI

    目标类

    创建BookService接口和实现类

    创建BookDao接口和实现类

    将dao和service配置到xml文件

    dao

    public interface BookDao { void addBook(); } public class BookDaoImpl implements BookDao { @Override public void addBook() { System.out.println("addBookDao"); } }

    service

    public interface BookService { void addBook(); } public class BookServiceImpl implements BookService { //方式一:之前 接口=实现类 // private BookDao bookDao=new BookDaoImpl(); //方式二:接口+setter private BookDao bookDao; public BookDao getBookDao() { return bookDao; } public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } @Override public void addBook() { } }

    配置类

    <?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-2.5.xsd"> <!-- 模拟spring执行过程 创建service实例: BookService bookService=new BookServiceImpl(); IOC<bean> 创建dao实例:BookDao bookDao=new BookDaoImpl(); IOC 将dao设置给service bookService.setBookDao(bookDao) DI<property> --> <!--创建service--> <bean id="bookService" class="cn.tedu.iocb.BookServiceImpl"> <property name="bookDao" ref="bookDao"/><!--通过set注入--> </bean> <!--创建dao--> <bean id="bookDao" class="cn.tedu.iocb.BookDaoImpl"/> </beans>

    测试

    @Test public void demo1(){ String XmlPath="applicationContext02.xml"; ApplicationContext context=new ClassPathXmlApplicationContext(XmlPath); BookService bookService = context.getBean("bookService", BookService.class); bookService.addBook(); }

    核心API

    BeanFactory: 这是一个工厂,用于生产任意bean,采用延迟加载,getBean的时候才会实例化ApplicationCOntext:是BeanFactory的子接口,功能更强大,当配置文件被加载就会实例化对象ClassPathXmlApplicationContext: 用于加载classpath(类路径或者src)下的知道xml 加载xml运行是位置–>/WEB-INF/classes/ …xmlFileSystemXmlApplicationContext 用于加载指定盘符下的xml,加载运行时位置–>WEB-INF/…xml通过java web ServletCOntext.getRealPath() 获得具体盘符

    装配Bean基于xml

    实例化方式

    3种bean实例化方法:默认工厂,静态工厂,实例工厂

    默认工厂我们一种用的就是,默认构造方法

    静态工厂

    常用语spring整合其他框架(或者工具)

    静态工厂:用于生成实例对象,所有的方法必须是static-----

    <!--将静态工厂创建的实例交给spring class 确定静态工厂全限定类名 factory-method 确定静态方法--> <bean id="user" class="cn.tedu.iocc.StaticFacoryUser" factory-method="getUser"/>

    实例工厂

    实例工厂:必须现有工厂实例对象,通过实例创建对象,提供所有方法都是非静态的

    <!--创建工厂实例--> <bean id="userFactory" class="cn.tedu.iocc.InstanceFatory"/> <!--获得user fatory-bean 确定工厂 fatory-metnod 确定普通方法--> <bean id="user" factory-bean="userFactory" factory-method="getUser"/>

    Bean的种类

    普通bean:之前操作都是普通bean,spring直接创建A实例,并返回FactoryBean:是一个特使的bean,具有工厂生成对象能力,只能生成特点对象.bean必须使用FactoryBean接口,此接口提供方法getObjec()用于获取特定的bean.先创建FB实例,使用调用getobject()方法,并发挥方法的返回值 FB fb=new FB() return fb.getObject()BeanFactoy和FactoryBean对比? BeanFactory: 工厂用于生成任意Bean,FactoryBean:特殊bean,用于生成另一个特定的bean例如:ProxyFactoryBean,此工厂bean用于生产代理 获得代理对象.AOP使用

    作用域

    作用域:用于确定spring创建bean实例的个数

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dtWaI1lv-1602062689259)(C:\Users\taget\Desktop\spring\spring.assets\image-20200904232306741.png)]

    取值:

    singleton 单例,默认值

    protorype 多列,没执行一次getBean就会获取一个实例

    <!--配置单例还是多列对象 scope="singleton" 单例 scope="prototype" 多列--> <bean id="user" class="cn.tedu.iocdscope.User" scope="prototype"></bean>

    声明周期

    初始化方法

    目标方法执行前后执行,将进行初始化或销毁

    目标类

    @Override public void addBook() { // bookDao.addBook(); System.out.println("方法执行了"); } public void myInit(){ System.out.println("我的初始化方法"); } public void myDestroy(){ System.out.println("我的销毁方法"); } //测试 @Test public void demo1() throws Exception { String XmlPath="applicationContext03.xml"; ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext(XmlPath); BookService bookService = context.getBean("bookServiceImpl", BookService.class); bookService.addBook(); //要求 1 容器必须close,销毁方法执行,而且还要是单例 //此方法接口没有定义,实现类提供 // context.getClass().getMethod("close").invoke(context); context.close(); }

    spring的配置

    <!-- init-method: 定义初始化方法 ,准备数据 destroy-method 用于配置销毁方法,清理资源等 --> <bean id="bookServiceImpl" class="cn.tedu.lifecycle.iocb.BookServiceImpl" init-method="myInit" destroy-method="myDestroy"/>

    BeanPostProcessor后处理Bean

    spring提供一种机制,只要实现此接口BeanPostProcessor,并将实现类提供给spring容器,spring容器将自动执行,在初始化方法前执行befor(),在初始化方法后执行after()

    spring提供工厂钩子,用于修改实例对象,可以生成代理对象,是AOP底层

    属性的依赖注入

    构造方法

    <bean id="accountService" class="cn.tedu.service.impl.AccountServiceImpl"> <constructor-arg index="0" value="老李"/> <constructor-arg index="1" value="15"/> <constructor-arg index="2" ref="now"/> </bean> <!--创建一个日期对象--> <bean id="now" class="java.util.Date"></bean>

    setter方法

    <!--创建一个日期对象--> <bean id="now" class="java.util.Date"></bean> <!--采用set方法注入 name:用于指定注入是调用的set方法名称 value:用于给基本类型和String提供值 ref:引用类型,srping容器里的 --> <bean id="accountService2" class="cn.tedu.service.impl.AccountServiceImpl1"> <property name="name" value="老邓"></property> <property name="age" value="20"></property> <property name="birthd" ref="now"></property> </bean>

    集合注入

    <bean id="accountServiceImpl2" class="cn.tedu.service.impl.AccountServiceImpl2"> <property name="myStrs"> <array> <value>AAA</value> <value>BBB</value> <value>CCC</value> </array> </property> <property name="lists"> <list> <value>AAA</value> <value>BBB</value> <value>CCC</value> </list> </property> <property name="sets"> <set> <value>AAA</value> <value>BBB</value> <value>CCC</value> </set> </property> <property name="myMap"> <map> <entry key="1" value="ik"></entry> <entry key="2"> <value>kk</value> </entry> </map> </property> <property name="properties"> <props> <prop key="p1">1</prop> <prop key="p2">2</prop> <prop key="p3">4</prop> </props> </property> </bean>

    spring的注解开发

    要开启注解扫描

    <!--告知spring在创建容器要扫码的包,配置所需要的标签不是在beans的约束中,而是一个名称为context名称空间约束中--> <context:component-scan base-package="service.impl"/>

    在类上修饰

    @Component(value = "accountServiceImpl") public class AccountServiceImpl implements IAccountService { @Override public void saveAccount() { System.out.println("service 执行了"); } } 层级的xml的配置 * <bean id="accountService" class="service.impl.AccountServiceImpl" * scope="" init-method="" destroy-method=""> * <property name="" value=""></property> * </bean> * 用于创建对象的 * 他们的作用就和xml配置文件中编写一个<bean>标签的功能是一样的 * Compoent: * 作用:用于吧当前类对象存入spring容器中 * 属性:value 用于主动bean的id当我们不写时,他默认值是当前类名,且首字母该小写 Controller service Repository 以上三个注解他们的作用和属性与compent一样的 他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰 * 用于注入数据的 * 他们的作用就和xml配置文件中的bean标签中写一个<property>标签的作用是一样的 Autowired: 作用:自动按照类型注入,只要容器中有唯一的bean对象类型和要注入的变量类型匹配,就可以注入成功,如果ioc容器中没有任何bean的类型和要注入的变量和类型匹配,则报错,如果ioc容器中有多个类型匹配使用,那么它会按照变量名称来进行匹配,如果我们不想改变量名称就使用Qualifier注解来一起使用 Qualifier: 作用:在按照类中主图的基础上在按照名称注入,它在给类成员注入时不能单独使用,但是在给方法参数注入时可以 属性:value: 用于指定注入bean的id Resource 作用:直接按照bean的id注入,它可以独立使用 属性:name:用于指定bean的id 以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现,另外,集合类型的注入只能同过xml来实现 Value 作用:用于注入基本类型和String类型的数据 属性:value:用于指定数据的值,他可以使用spring中的el表达式 spel的写法: ${表达式} * 用于改变作用范围的 * 他们的作用集合在bean标签中使用scope属性实现的功能是一样的 Scope 作用:用于指定bean的作用范围 属性:value: single单例,prototype多列 * 和生命周期相关(了解) * 他们的作用就和在bean标签中使用initmethod和destory-method的作用是一样的 PreDestroy 作用:用于指定销毁方法 PostConstruct 作用:用于指定初始化方法

    创建对象的注解,compent,controller,service,repostory

    @Component(value = "accountServiceImpl") public class AccountServiceImpl implements IAccountService { private AccountDaoImpl accountDao; @Override public void saveAccount() { accountDao.saveAccount(); System.out.println("service 执行了"); } }

    用于注入数据的注解Autowrite,Qualifier,Resource

    @Component(value = "accountServiceImpl") public class AccountServiceImpl implements IAccountService { @Autowired @Qualifier(value = "accountDao") private AccountDaoImpl accountDao; @Override public void saveAccount() { accountDao.saveAccount(); System.out.println("service 执行了"); } } //qualifire修饰属性时不能单独用,他是用来指定id的当出现多个类型相同的bean对象时两个配合使用,如果不想使用这个注解,直接使用Resource也可以

    项目练习

    准备环境

    <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>commons-dbutils</groupId> <artifactId>commons-dbutils</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency> </dependencies> create database eesy; use eesy CREATE table account(id int PRIMARY KEY auto_increment,name varchar(40),money float)character set utf8 collate utf8_general_ci; INSERT into account(name,money)values('aaa',1000),('bbb',1000),('ccc',1000)

    service

    package cn.tedu.service; import cn.tedu.entity.Account; import java.util.List; public interface IAccountService { /** * 查询所有 */ List<Account> findAllAccount(); /** * 查询一个 * @return */ Account findAccountById(Integer id); /** * 添加一个 * @param account */ void saveAccount(Account account); /** * 更新 */ void updateAccount(Account account); /** * 删除 */ void deleteAccount(Integer id); } package cn.tedu.service.impl; import cn.tedu.dao.IAccountDao; import cn.tedu.entity.Account; import cn.tedu.service.IAccountService; import java.util.List; /** * 账户业务层实现类 */ public class AccountService implements IAccountService { private IAccountDao accountDao; public IAccountDao getAccountDao() { return accountDao; } public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } @Override public List<Account> findAllAccount() { return accountDao.findAllAccount(); } @Override public Account findAccountById(Integer id) { return accountDao.findAccountById(id); } @Override public void saveAccount(Account account) { accountDao.saveAccount(account); } @Override public void updateAccount(Account account) { accountDao.updateAccount(account); } @Override public void deleteAccount(Integer id) { accountDao.deleteAccount(id); } }

    dao

    package cn.tedu.dao; import cn.tedu.entity.Account; import java.util.List; public interface IAccountDao { /** * 查询所有 */ List<Account> findAllAccount(); /** * 查询一个 * @return */ Account findAccountById(Integer id); /** * 添加一个 * @param account */ void saveAccount(Account account); /** * 更新 */ void updateAccount(Account account); /** * 删除 */ void deleteAccount(Integer id); } package cn.tedu.dao; import cn.tedu.entity.Account; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import java.sql.SQLException; import java.util.List; public class AccountDaoImpl implements IAccountDao { private QueryRunner runner; public QueryRunner getRunner() { return runner; } public void setRunner(QueryRunner runner) { this.runner = runner; } @Override public List<Account> findAllAccount() { try { return runner.query("select * from account",new BeanListHandler<Account>(Account.class)); } catch (SQLException e) { e.printStackTrace(); } return null; } @Override public Account findAccountById(Integer id) { try { return runner.query("select * from account where id=?",new BeanHandler<Account>(Account.class),id); } catch (SQLException e) { e.printStackTrace(); } return null; } @Override public void saveAccount(Account account) { try { runner.update("insert into account (name,money)value(?,?)",account.getName(),account.getMoney()); } catch (SQLException e) { e.printStackTrace(); } } @Override public void updateAccount(Account account) { try { runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId()); } catch (SQLException e) { e.printStackTrace(); } } @Override public void deleteAccount(Integer id) { try { runner.update("delete from account where id=?",id); } catch (SQLException e) { e.printStackTrace(); } } }

    配置文件

    <?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-3.0.xsd"> <!--配置service--> <bean id="accountService" class="cn.tedu.service.impl.AccountService"> <property name="accountDao" ref="accountDao"/> </bean> <!--配置dao--> <bean id="accountDao" class="cn.tedu.dao.AccountDaoImpl"> <property name="runner" ref="runner"></property> </bean> <!--配置QueryRunner--> <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"> <constructor-arg name="ds" ref="dataSource"></constructor-arg> </bean> <!--配置数据源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!--连接数据库必备信息--> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/eesy"/> <property name="user" value="root"/> <property name="password" value="root"/> </bean> </beans>

    测试

    /** * 使用junit单元测试 */ public class AccountServiceTest { @Test public void findAll() { //获取容器 ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); IAccountService service= (IAccountService) context.getBean("accountService"); service.findAllAccount().forEach(System.out::print); } @Test public void findOne() { ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); IAccountService service= (IAccountService) context.getBean("accountService"); System.out.println(service.findAccountById(1)); }

    一步一步的去除xml

    去除bean标签

    @Repository public class AccountDaoImpl implements IAccountDao { @Autowired private QueryRunner runner; @Service public class AccountService implements IAccountService { @Autowired private IAccountDao accountDao;

    这里只是把我们自己写的类给创建了,但是我们导入的jar包里的类,我们无法进行加入注解

    去除第三方jar包提供的对象,使用注解

    @Configuration public class SpringConfiguration { @Bean("runner") @Scope("prototype") public QueryRunner createaQueryRunner(DataSource dataSource){ return new QueryRunner(dataSource); } @Bean public DataSource dataSource() throws PropertyVetoException { ComboPooledDataSource source=new ComboPooledDataSource(); source.setDriverClass("com.mysql.jdbc.Driver"); source.setJdbcUrl("jdbc:mysql://localhost:3306/eesy"); source.setUser("root"); source.setPassword("root"); return source; }

    但是这样把配置写死了,于是我们可以使用另外一个注解来读取配置文件PropertySource

    @PropertySource("classpath:jdbcConfig.properties") public class JdbcConfiguration { @Value("${jdbc.driver}") private String driverClass; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("runner") @Scope("prototype") public QueryRunner createaQueryRunner(DataSource dataSource){ return new QueryRunner(dataSource); } @Bean//表示创建一个对象 public DataSource dataSource() throws PropertyVetoException { ComboPooledDataSource source=new ComboPooledDataSource(); source.setDriverClass("com.mysql.jdbc.Driver"); source.setJdbcUrl("jdbc:mysql://localhost:3306/eesy"); source.setUser("root"); source.setPassword("root"); return source; } jdbc.driver=jdbc:mysql://localhost:3306/eesy jdbc.url=com.mysql.jdbc.Driver jdbc.username=root jdbc.password=root

    当我们有多个配置类的时候,有两种方式来进行加载

    第一种,在AnnotationCOnfigApplicationCOntext里面写多个配置类的class

    @Test public void testSave() { ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfiguration.class, JdbcConfiguration.class); IAccountService service= (IAccountService) context.getBean("accountService"); service.findAllAccount().forEach(System.out::print); }

    第二种使用Import来进行导入子配置类

    @Configuration @ComponentScan("cn.tedu") @Import(JdbcConfiguration.class) public class SpringConfiguration { @Bean("runner") @Scope("prototype") public QueryRunner createaQueryRunner(DataSource dataSource){ return new QueryRunner(dataSource); }

    Qualifier注解的使用

    @Configuration @ComponentScan("cn.tedu") @Import(JdbcConfiguration.class) public class SpringConfiguration { @Bean("runner") @Scope("prototype") //这里隐藏了一个Autowrite注解,这是多数据源切换的用法 public QueryRunner createaQueryRunner(@Qualifier("ds1") DataSource dataSource){ return new QueryRunner(dataSource); } @Bean("dataSource") public DataSource dataSource() throws PropertyVetoException { ComboPooledDataSource source=new ComboPooledDataSource(); source.setDriverClass("com.mysql.jdbc.Driver"); source.setJdbcUrl("jdbc:mysql://localhost:3306/eesy"); source.setUser("root"); source.setPassword("root"); return source; } @Bean("ds1") public DataSource dataSource1() throws PropertyVetoException { ComboPooledDataSource source=new ComboPooledDataSource(); source.setDriverClass("com.mysql.jdbc.Driver"); source.setJdbcUrl("jdbc:mysql://localhost:3306/eesy"); source.setUser("root"); source.setPassword("root"); return source; } }

    整合junit

    每次都去加载容器,比较麻烦

    @Test public void findAll() { //获取容器 ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); IAccountService service= (IAccountService) context.getBean("accountService"); service.findAllAccount().forEach(System.out::print); } @Test public void findOne() { ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); IAccountService service= (IAccountService) context.getBean("accountService"); System.out.println(service.findAccountById(1)); }

    改造后

    public class AccountServiceTest { ApplicationContext context=null; @Before//每次执行测试方法前都会先去执行它 public void findAll() { //获取容器 context=new ClassPathXmlApplicationContext("applicationContext.xml"); } @Test public void findOne() { IAccountService service= (IAccountService) context.getBean("accountService"); System.out.println(service.findAccountById(1)); } 应用程序的入口 main方法 junit不会管我们是否才有spring框架 在执行测试方法是,junit根本不知道我们是不是使用了spring框架,所以也就不会为我们读取配置文件/配置类创建spring核心容器 由以上得知,当测试方法执行时,没有ioc容器,就算写了autowrite也不会注入

    整合步骤

    导入spring整合junit的jar(坐标)(这里版本不要太高了,本人在这徘徊了大半天)

    <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency>

    使用junit提供的一个注解吧原有的main方法替换了,替换成spring提供的,加上@Runwith注解

    告知spring运行器,spring和ioc创建是基于xml还是注解的,并说明位置 @ContextConfiguration注解

    属性:locations:指定xml文件的位置,加上classpath关键字,表示类路径下

    classes:指定注解类所在位置

    当我们只有spring5.x版本的时候,要修junit必须是4.12及以上

    代码演示

    @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfiguration.class) public class AccountServiceTest { @Autowired IAccountService service; @Test public void findOne() { // IAccountService service= (IAccountService) context.getBean("accountService"); System.out.println(service.findAccountById(1)); } }
    Processed: 0.011, SQL: 8