1.Spring框架介绍:
Spring是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。
Spring可以去整合表现层,业务层,持久层的开源的框架,在表现层提供了与Struts2框架的整合,在业务逻辑层可以管理事务和记录日志,在持久层可以整合Hibernate和JdbcTemplate等技术。
框架的主要优势之一就是分层架构,分层架构允许使用者选择哪一个组件。
Spring的核心就是控制反转(IOC控制反转)和面向切面AOP。
1.1 Spring的优点
1.方便解耦,简化开发,Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理。IOC的作用。
2.AOP编程的支持,Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。(可扩展性)
3.声明式事务的支持,只需要通过配置就可以完成对事务的管理,而无需手动编程。
有两种实现方式:一种是动态代理,一种是静态代理
4.方便程序的测试,Spring对Junit4支持,可以通过注解方便的测试Spring程序。
5.方便集成各种优秀框架,Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)的直接支持。
6.降低JavaEE API的使用难度,Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。
2. Spring—IOC
2.1 什么是IOC
IOC——Inverse of Control ,控制反转,将对象的创建权力反转给Spring框架!!
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。
Spring工厂读取配置文件
2.2 写一个IOC程序
首先我们创建一个Java maven的项目
在项目src目录下的main目录中的java目录下随便创建一个目录然后在该目录下创建一个service的包,包中写一个接口
public interface UserService {
public void hello();
}
再写一个接口实现类
public class UserServiceImpl implements UserService {
@Override
public void hello() {
System.out.println("IOC!!!");
}
}
然后去test下写一个测试类测试一下
public class test {
@Test
public void run(){
UserService userService= new UserServiceImpl();
userService.hello();
}
}
ok了
如果我们没有IOC(控制反转)就需要向上面一样自己手动new一个对象去实现这个hello方法。
如果我们要实现IOC(控制反转)该怎么做?
首先,编写Spring核心的配置文件,在src目录下创建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">
<!--IOC管理bean-->
<bean id="userService" class="com.qcbyjy.service.UserServiceImpl" />
</beans>
然后引入一个标签,该标签有两个属性一个id 一个class,id就是你给这个对象起的名字,class就是你的这个类的所在的位置。
在spring的配置文件中配置一个bean,就相当于把这个类交给Spring的IOC容器去管理,Spring管理的对象叫做bean对象。
然后在测试类里写一个测试方法
@Test
public void run1(){
//spring的工厂对象 bean工厂
//去读取spring的配置文件
//Spring 的工厂是负责加载并管理所有的
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml");
//工厂对象的方法
UserService userService= (UserService) ac.getBean("userService");
//调用userService实现的方法
userService.hello();
}
我们来看一下这Application这个接口,这个接口最下面有两个实现类,一个ClassPathXmIApplicaitonContext(加载类路径下的配置文件),一个是FileSystemXmlAppcationContext(就是直接把配置文件的地址写上)
2.3 两种创建方式的对比
自己new对象
@Test
public void run(){
UserService userService= new UserServiceImpl();
UserService userService1= new UserServiceImpl();
System.out.println(userService);
System.out.println(userService1);
}
工厂创建对象的方式
@Test
public void run1(){
//spring的工厂对象 bean工厂
//去读取spring的配置文件
//Spring 的工厂是负责加载并管理所有的
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml");
//工厂对象的方法
UserService userService= (UserService) ac.getBean("userService");
UserService userService1= (UserService) ac.getBean("userService");
//调用userService实现的方法
System.out.println(userService);
System.out.println(userService1);
}
我们会发现工厂创建的是同一对象,就是说在不做任何改变的情况下,我们使用spring的工厂创建对象的时候,默认的是单例模式。
2.4 Spring框架的Bean管理的配置文件方式
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属性指定的方法
单例对象的销毁:随着容器工厂的销毁而销毁
多例对象的销毁:垃圾回收机制进行回收
所以这个destroy-method的方法我们没法看到,只能看一下init_method的实现。
首先,在UserServiceImpl类下的写一个init的方法。
/**
* 对象被创建前的初始化的方法
*/
public void init(){
System.out.println("init方法的执行");
}
指定初始化的方法,然后我们去测试一下效果
public void run1(){
//spring的工厂对象 bean工厂
//去读取spring的配置文件
//Spring 的工厂是负责加载并管理所有的
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml");
//工厂对象的方法
UserService userService= (UserService) ac.getBean("userService");
userService.hello();
}
这个初始化方法在单例和多例模式下运行的时机不太一样,也可以说单例和多例模式下创建对象的时机是不一样的。
我们来看一下:
先在创建工厂对象下加一行分隔符
然后在单例模式(默认)下运行看一下,
我们可以看到在单例模式在创建工厂的时候就把对象也给创建了。
多例模式下再运行看一下
就会发现我们多例模式下,是创建完工厂后,当需要创建对象时才会创建对象,进行初始化。
2.5 Spring实例对象的三种方式
默认
无参数的构造方法(基本上都是默认)
<bean id="userService" class="com.qcby.service.UserServiceImpl"/>
静态工厂实例化
使用静态工厂实例化,首先要去写一个静态的工厂类
/**
* 利用静态工厂的方法创建对象
*/
public class StaticFactory {
public static UserService createUseService(){
System.out.println("通过静态工厂的方式创建对象");
return new UserServiceImpl();
}
}
然后我们去application.xml的配置文件中,配置该对象
<bean id="userServiceFactory" class="com.qcby.Factory.StaticFactory" factory-method="createUseService" />
主要的就是在最后指定一下调用的静态工厂的方法,然后我们来测试一下。
@Test
public void run3(){
//创建工厂对象
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml");
UserService userService = (UserService) ac.getBean("userServiceFactory");
userService.hello();
}
实例工厂实例化
再来说一下工厂实例化的过程,所谓的工厂 实例化就需要我们去创建一个普通的工厂类,然后再写一个创建对象的方法。
public class UserFactory {
public UserService createUserService1(){
System.out.println("通过工厂实例化的方法去创建对象");
return new UserServiceImpl();
}
}
因为这个类是一个普通的类,无法直接调用该类中的方法,所以,我们再配置文件中,需要配置一个工厂类,这样才能调用到里面的方法。
<bean id="factory" class="com.qcby.Factory.UserFactory" />
<bean id="userService" factory-bean="factory" factory-method="createUserService1" />
写一个测试类
/**
* 实例工厂的方式获取bean对象
*/
@Test
public void run4(){
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml");
UserFactory userFactory =(UserFactory) ac.getBean("factory");
UserService userService = (UserService) ac.getBean("userServiceFactory");
userService.hello();
}
3. DI注入
3.1 什么是DI注入
IOC和DI的概念
IOC:Inverse of Control,控制反转,是一种思想,将对象的创建权反转给Spring!!
DI:Dependency Injection,依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!!
简单的举个例子,
我们先写一个Student的类
public class Student {
private String name;
private Integer age;
private String classname;
public Student() {
}
public Student(String name, Integer age, String classname) {
this.name = name;
this.age = age;
this.classname = classname;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getClassname() {
return classname;
}
public void setClassname(String classname) {
this.classname = classname;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", classname='" + classname + '\'' +
'}';
}
}
然后使用默认方法构建对象
<bean id="student" class="com.qcby.model.Student"/>
测试方法
@Test
public void run5(){
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml");
Student student=(Student) ac.getBean("student");
System.out.println(student);
}
然后我们会发现我们创建的类没有值
那我们试如何给对象的属性注入值呢?
以前没有学Spring的时候,我们有两种方式,一种Set方法,一种是构造器。
Student student1=new Student();
//set方法
student1.setName("zhangsan");
student1.setAge(18);
student1.setClassname("bigdata");
System.out.println(student1);
//构造器
Student student2=new Student("lisi",21,"bigdata");
System.out.println(student2);
当我们有了Spring之后就可以不用这么做了,那么我们该如何做呢 ?
也是分两种方式:
Set方法注入和构造器注入
我们首先先创建一个OrderService的接口,里面有一个保存订单的方法
public interface OrderService {
public void saveOrder();
}
再写一个OrderServiceImpl的实现类
public class OrderServiceImpl implements OrderService{
@Override
public void saveOrder() {
System.out.println("业务层保存订单!!!");
}
}
我们一般业务层要调用持久层的方法,所以我们去创建一个OrderDao的接口和一个OrderDaoImpl的实现类
public interface OrderDao {
public void saveOrder();
}
public class OrderDaoImpl implements OrderDao{
@Override
public void saveOrder() {
System.out.println("持久层保存订单");
}
}
然后我们去application.xml中配置文件配置
3.2 set方法注入
<bean id="orderDao" class="com.qcby.dao.OrderDaoImpl"/>
<bean id="orderService" class="com.qcby.service.OrderServiceImpl">
<property name="orderDao" ref="orderDao"/>
<property name="name" value="张三"/>
<property name="Account" value="18" />
</bean>
3.3 构造器方法注入
<bean id="student" class="com.qcby.model.Student">
<constructor-arg name="name" value="李四"/>
<constructor-arg name="age" value="18"/>
<constructor-arg name="classname" value="bigdata"/>
</bean>
Student student=(Student) ac.getBean("student");
System.out.println(student);
3.4 数组、集合、properties的注入
首先去创建一个类,类里面写一个数组,然后写一个set方法,并重写一个toString的方法
public class CollectionBean {
private String[] strs;
private List<String> list;
private Map<String,String> map;
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setList(List<String> list) {
this.list = list;
}
public void setStrs(String[] strs) {
this.strs = strs;
}
@Override
public String toString() {
return "CollectionBean{" +
"strs=" + Arrays.toString(strs) +
", list=" + list +
", map=" + map +
'}';
}
}
然后去application.xml的文件中注入值
<bean id="collectionBean" class="com.qcby.model.CollectionBean">
<property name="strs">
<array>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</array>
</property>
<property name="list">
<!-- 这个地方用list也行 -->
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</list>
</property>
<property name="map">
<map>
<entry value="a" key="张三"/>
<!-- 如果是引用数据类型可以使用key-ref="" value-ref="" -->
<entry value="b" key="李四"/>
</map>
</property>
</bean>
写一个测试方法测试一下
@Test
public void run7(){
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml");
CollectionBean collectionBean=(CollectionBean) ac.getBean("collectionBean");
System.out.println(collectionBean);
}
唯一有点不同的就是properties
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
3.5 多配置文件形式
就是我们感觉写在一文件里面太麻烦了,想要在多个文件中写,行不行?
当然可以了,我们有两种方式可以进行多文件的配置,接下来我们演示一下多文件配置的方式,先把第一个application中的student注释掉。
然后我们会发现再使用工厂对象创建Student的对象就不行了
然后我们去resources下创建一个application01.xml的文件,把Student类交给Spring去管理
<?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="student" class="com.qcby.model.Student">
<constructor-arg name="name" value="李四"/>
<constructor-arg name="age" value="18"/>
<constructor-arg name="classname" value="bigdata"/>
</bean>
</beans>
然后再创建工厂对象的时候使用写两个配置文件
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml","application01.xml");
再运行的时候就可以了
还有一种方式就是:我不在创建工厂对象的时候写两个配置文件
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml");
我们可以在 application文件中用标签,引入其他的文件,也是可以的
<import resource="application01.xml"/>
4. Spring-IOC开发中的实际应用(demo)
4.1 创建数据库
创建一个数据库
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);
4.2 创建项目
4.2.1 创建一个JavaMaven的项目
上面有提到过,忘记的往上翻一下
4.2.2 导入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</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>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
4.3 创建dao和service的演示类
创建实体类(Account)
public class Account {
private Integer id;
private String name;
private Integer money;
public Account() {
}
public Account(Integer id, String name, Integer money) {
this.id = id;
this.name = name;
this.money = money;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
创建Dao的接口
public interface AccountDao {
public List<Account> SelectAll();
}
Dao层的实现类
public class AccountDaoImpl implements AccountDao{
@Override
public List<Account> SelectAll() {
DruidDataSource dataSource=new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring_db");
dataSource.setUsername("root");
dataSource.setPassword("password");
List<Account> list=new ArrayList<Account>();
Connection connection=null;
PreparedStatement statement= null;
ResultSet resultSet=null;
try {
//获取连接
connection=dataSource.getConnection();
//编写sql语句
String sql="SELECT * FROM `account`";
//预编译
statement = connection.prepareStatement(sql);
//查询
resultSet=statement.executeQuery();
// 遍历封装数据
while(resultSet.next()){
Account account =new Account();
account.setId(resultSet.getInt("id"));
account.setName(resultSet.getString("name"));
account.setMoney(resultSet.getInt("money"));
list.add(account);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try{
connection.close();
}catch (SQLException e){
e.printStackTrace();
}
try{
statement.close();
}catch (SQLException e){
e.printStackTrace();
}
}
return list;
}
}
然后创建Service层的接口
public interface AccountService {
public List<Account> selectAll();
}
Service的实现类
public class AccountServiceImpl implements AccountService{
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public List<Account> selectAll() {
return accountDao.SelectAll();
}
}
application.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="accountService" class="com.qcby.service.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<bean id="accountDao" class="com.qcby.dao.AccountDaoImpl"/>
</beans>
最后测试
public class Demo1 {
@Test
public void run1(){
ApplicationContext ac= new ClassPathXmlApplicationContext("application.xml");
AccountService accountService=(AccountService) ac.getBean("accountService");
List<Account> accounts=new ArrayList<Account>();
accounts=accountService.selectAll();
System.out.println(accounts);
}
}
5. 注解开发的方式
5.1 半注解半配置文件的形式
我们先来创建一个类UserService的接口
public interface UserService {
public void hello();
}
在写一个实现类
/**
* SpringIOC半配置文件半注解的形式
* @Component(value="")这个注解就相当于<bean id="userService" class="com.qcby.service.UserServiceIpml"/>
* value就是相当于id,如果不写value就是把类名的首字母小写作为id
*
*/
@Component(value = "userService")
public class UserServiceIpml implements UserService{
@Override
public void hello() {
System.out.println("SpringIOC,半注解半配置文件的形式");
}
}
如果我们按照上文所学的知识就是在application中写写这么一个标签将这个类交给Spring去管理,但是我们现在可以用一种更简单的方式,把这个类交给Spring去管理,就是在该类上加一个@Component注解, @Component注解有一个value的属性,就是相当于标签中的id属性,可以不写,不写就默认是类名首字母小写(userService)
除此之外我们要去application.xml文件中加一个约束,
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
如果不会加的直接把下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"
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">
测试方法和以前一样
@Test
public void run2(){
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml");
UserService userService=(UserService) ac.getBean("userService");
userService.hello();
}
5.2 常用的注解
bean管理类常用的4个注解(作用相同,推荐使用在不同分层上)
@Component 普通的类
@Controller 表现层
@Service 业务层
@Repository 持久层
依赖注入常用的注解
@Value 用于注入普通类型(String,int,double等类型)
@Autowired 默认按类型进行自动装配(引用类型)
@Qualifier 和@Autowired一起使用,强制使用名称注入
@Resource Java提供的注解,也被支持。使用name属性,按名称注入
对象生命周期(作用范围)注解
@Scope 生命周期注解,取值singleton(默认值,单实例)和prototype(多例)
初始化方法和销毁方法注解(了解)
@PostConstruct 相当于init-method
@PreDestroy 相当于destroy-method
5.3 通过注解的方式DI注入
创建一个Car的类
@Component("car")
public class Car {
@Value("小米su7")
private String name;
@Value("300000")
private Double price;
@Autowired
private Student owner;
public Car() {
}
public Car(String name, Double price, Student owner) {
this.name = name;
this.price = price;
this.owner = owner;
}
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;
}
public Student getOwner() {
return owner;
}
public void setOwner(Student owner) {
this.owner = owner;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
", owner='" + owner + '\'' +
'}';
}
}
再写一个Student的类
@Component("student")
public class Student {
@Value("小明")
private String name;
@Value("24")
private Integer age;
@Value("大数据")
private String classname;
public Student() {
}
public Student(String name, Integer age, String classname) {
this.name = name;
this.age = age;
this.classname = classname;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getClassname() {
return classname;
}
public void setClassname(String classname) {
this.classname = classname;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", classname='" + classname + '\'' +
'}';
}
}
注意:要把配置文件中的application.xml中的扫描包改成这两个类所在的包
然后编写测试方法
@Test
public void run3(){
ApplicationContext ac=new ClassPathXmlApplicationContext("application.xml");
Car car = (Car) ac.getBean("car");
System.out.println(car);
}
剩下的哪些注解就不一一演示了,有兴趣的自己探索一下吧
对了,这个注解的方式注入值的时候,不用自己生成set方法,因为他直接在你要加的属性的加的注释,所以就Spring是框架直接给你的属性注入的值,如果需要set方法注入,直接在set方法上用@Value的注解,就是使用set方法注入
5.4 通过纯注解的方式开发
顾名思义,就是就是只用注解不写配置文件的方式来进行开发。
但是需要写一个配置类,就是用来代替配置文件的东西。
//声明当前的类是配置类
@Configuration
//指定扫描的包的位置
@ComponentScan("com.qcby")
public class SpringConfig {
}
写一个实体类
@Component
public class Order {
@Value("保定")
private String address;
public Order() {
}
public Order(String address) {
this.address = address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Order{" +
"address='" + address + '\'' +
'}';
}
}
测试类
@Test
public void run4(){
ApplicationContext ac =new AnnotationConfigApplicationContext(SpringConfig.class);
Order order = (Order) ac.getBean("order");
System.out.println(order);
}
常用的注解总结
@Configuration 声明是配置类
@ComponentScan 扫描具体包结构的
@Import注解 Spring的配置文件可以分成多个配置的,编写多个配置类。用于导入其他配置类
@Bean注解 只能写在方法上,表明使用此方法创建一个对象,对象创建完成保存到IOC容器中
@Bean和@Component的区别:
@Component是加在类上的
@Bean是加在方法上的
本质上来说都是告诉Spring框架要创建一个类
举个栗子
@Bean
public void createDataSource(){
DruidDataSource dataSource=new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring_db");
dataSource.setUsername("root");
dataSource.setPassword("password");
}
6.Spring整合junit的测试
我们在上面写测试方法的时候就每次都要读取配置文件或者配置类创建一个工厂对象,然后去获取bean对象,这就造成了一个代码冗余的问题。
为了解决这个问题,Spring提供了整合Junit单元测试的技术,可以简化测试开发。下面开始学习该技术。
必须先有Junit单元测试的环境,也就是说已经导入Junit单元测试的jar包。咱们已经导入过了。使用的是4.12版本
再导入spring-test的坐标依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>\
<version>5.0.2.RELEASE</version>
<scope>test</scope>
</dependency>
然后我们去model包下写一个User的类
public class User {
public void sayHello(){
System.out.println("hello");
}
}
创建一个application01.xml的配置文件,将写好的User类交给Spring管理
<?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">
<bean id="user" class="com.qcby.model.User"/>
</beans>
这时候我们自己写测试的话按照以上的方式就是这么写
public class Test {
@Test
public void run1(){
ApplicationContext ac= new ClassPathXmlApplicationContext("application01.xml");
User user=(User) ac.getBean("user");
user.sayHello();
}
}
然后我们导入依赖的时候不是导入了整合junit的测试了吗,然后我们就可以用Spring整合的junit去测试一下。
/**
* @RunWith(SpringJUnit4ClassRunner.class)声明该类是是一个测试单元
* @ContextConfiguration(value = "classpath:application01.xml")指定Spring配置文件的位置,加载该配置文件
*/
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(value ="classpath:application01.xml")
public class Test01 {
@Autowired
public User user;
@Test
public void run() {
user.sayHello();
}
}
主要是@RunWith(value = SpringJUnit4ClassRunner.class)声明是一个测试单元
@ContextConfiguration(value ="classpath:application01.xml")声明要加载的配置文件或者配置类
补充一点
@Autowired是按照类型注入,因为是单例的所以就可以直接按类型找到并注入,可以节省内存速度