Spring学习

1 Spring简介

1.1 Spring概念

网址:https://spring.io/
1. Spring是一个java的开源框架

2. Spring是于2003 年兴起的一个轻量级的Java开发框架,由Rod Johnson在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。

3. Spring框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。

4. Spring使用基本的JavaBean来完成以前只可能由EJB(企业级Java 构件EJB(Enterprise JavaBeans))完成的事情.pring的用途不仅限于服务器端的开发。

5. 从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。

6. Spring框架,可以解决对象创建以及对象之间依赖关系的一种框架。且可以和其他框架一起使用;例如:Spring与Struts2整合,  Spring与Hibernate整合,Spring与MyBatis整合 (Spring起到整合(粘合)作用的一个框架)

1.2 Spring核心

1. Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。

1.2.1 控制反转IoC:Inversion of Control

1. 控制反转IoC:Inversion of Control
    是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。
    通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
   
2. 控制反转中最常见的方式叫做依赖注入(Dependency Injection,简称DI)。还有一种方式叫“依赖查找”(Dependency Lookup)。
(1)依赖注入DI:Dependency Injection
组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。容器全权负责的组件的装配,它会把符合依赖关系的对象通过JavaBean属性或者构造函数传递给需要的对象。通过JavaBean属性注射依赖关系的做法称为设值方法注入(Setter Injection);将依赖关系作为构造函数参数传入的做法称为构造器注入
    
(2)依赖查找DL:Dependency Lookup
容器提供回调接口和上下文条件给组件。EJB和Apache Avalon 都使用这种方式。这样一来,组件就必须使用容器提供的API来查找资源和协作对象,仅有的控制反转只体现在那些回调方法上(也就是上面所说的 类型1):容器将调用这些回调方法,从而让应用代码获得相关资源。
    

1.2.2 面向切面AOP

面向切面AOP:
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

1.2 Spring的学习意义

1. 方便解耦,简化开发:Spring就是一个大工厂,可以将所有对象的创建,对象间的依赖关系维护工作,都交给Spring管理 
2. AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
3. 声明式事务的支持:只需要通过配置就可以完成对事务的管理,而无需手动编程
4. 方便程序的测试
Spring对Junit的支持,可以通过注解方便的测试Spring程序
5.方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)的直接支持
6. 降低JavaEE API的使用难度
Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。

1.4 Spring模块组成

在这里插入图片描述

2. Spring IOC

2.1 Spring IOC的概念

1. Ioc----Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。
2. Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

3. 控制是谁控制谁的问题,直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;

4. 控制正转是程序在对象中主动控制创建依赖对象
5. 控制反转是loc容器控制对象,主要控制了外部资源获取(不只是对象包括比如文件等),loc帮忙创建本对象的依赖对象,并将依赖对象注入本对象

在这里插入图片描述

2.3 使用工厂模式设计IOC容器

IOC容器的底层实现其实就是利用工厂设计模式。接下来我们通过工厂设计模式模拟一个小型的IOC容器

2.3.1 简单IOC案例程序

(1)CustomerDao接口
package edu.xja.dao;

/**
 * 消费者接口
 */
public interface CustomerDao {
    /**
     * 消费商品
     */
    public void save();
}

(2)CustomerDaoMySQLImpl
import edu.xja.dao.CustomerDao;

/**
 * 消费者接口实现类
 */
public class CustomerDaoMySQLImpl  implements CustomerDao {
    @Override
    public void save() {
        System.out.println("把客户数据保存到mysql");
    }
}

(3)CustomerDaoOracleImpl
package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;

public class CustomerDaoOracleImpl implements CustomerDao {
    @Override
    public void save() {
        System.out.println("把客户数据保存到oracle");
    }
}

(4)2)在src目录编写beans.properties配置文件
对象类名=对象全限定名
customerDao=edu.xja.dao.impl.CustomerDaoMySQLImpl
(5) 编写BeanFactory类
package edu.xja.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * BeanFactory 生产对象的工厂类
 */
public class BeanFactory {
   //1. 定义一个属性 properties属性对象
    private static Properties properties = new Properties();

    //2. 使用静态代码块,加载properties属性文件
    static{
        //(1)使用本类class文件获取输入流
        InputStream inputStream = BeanFactory.class.getResourceAsStream("/beans.properties");

        try {
            //(2)使用properties属性对象加载输入流
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("加载beans.properties文件失败");
        }


       
    }

    /**
     * 根据输入的依赖类名称,获取依赖对象
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName){
        //1. 通过beanName在属性properties文件中找到依赖类的全限定名
        String allBeanName = properties.getProperty(beanName);
        try {
             //2.利用反射获取依赖类的class对象,返回class对象创建的依赖类对象
            return    Class.forName(allBeanName).newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
       return null;
    }

}

(6) CustomerService接口
package edu.xja.service;

/**
 * CustomerService接口
 */
public interface CustomerService {
    public void cust();
}

(7) CustomerServiceImpl接口实现类

public class CustomerServiceImp implements CustomerService {
    //1. 获取依赖类接口对象
    private CustomerDao customerDao = (CustomerDao)BeanFactory.getBean("customerDao");

    @Override
    public void cust() {
        //2.调用依赖接口的方法
        customerDao.save();
    }
}
(8)测试类
package edu.xja.service.impl;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class CustomerServiceImpTest {
private CustomerServiceImp serviceImp = new CustomerServiceImp();
    @Test
    void cust() {
        serviceImp.cust();
    }
}

在这里插入图片描述

此时是将数据保存到mysql,若是想将对象放入oracle,只需要在properties文件中修改customerDao对应的值,不用在源代码中修改,大大降低耦合性

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

2.3.2 IOC使用集合装依赖对象

(1) 创建注解MyRepository 用于依赖注入
/**
 *  注解
 */
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD)
public @interface MyRepository {
//默认为空格
    String value() default "";
}

(2) CustomerServiceImpl

public class CustomerServiceImp implements CustomerService {
    //1. 使用注解给出依赖类类名
    @MyRepository("customerDao")
    private CustomerDao customerDao ;
    @Override
    public void cust() {
        //2.调用依赖接口的方法
        customerDao.save();
    }
}
(3) bean工厂类BeanFactory2

2.4 Spring IOC的案例

2.4.1 创建Spring工程

在这里插入图片描述

2.4.2 引入Spring依赖jar包

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.3</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>5.3.3</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.3</version>
</dependency>
或者 简写的
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.3</version>
</dependency>

2.4.3 编写Dao接口和实现类

(1) Dao接口
package edu.xja.dao;

public interface CustomerDao {
    /**
     * 存储方法
     */
    void save();
}

(2)实现类
package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;

public class CustomerMySQLDaoImpl implements CustomerDao {
    public CustomerMySQLDaoImpl() {
    }

    /**
     * 初始化方法
     */
    void before(){
        System.out.println("初始化");
    }

    /**
     * 存储到mysql
     */
    public void save() {
        System.out.println("存储用户信息到mysql数据库");
    }

    /**
     * 执行结束方法
     */
    void after(){
        System.out.println("执行完毕");
    }

}

package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;

public class CustomerOracleDaoImpl implements CustomerDao {
    public CustomerOracleDaoImpl() {
    }

    /**
     * 初始化方法
     */
    void before(){
        System.out.println("初始化");
    }


    /**
     * 存储到oracle数据库
     */
    public void save() {
        System.out.println("存储用户信息到Oracle数据库");
    }

    /**
     * 执行结束方法
     */
    void after(){
        System.out.println("执行完毕");
    }

}

2.4.4 在resources目录下建立applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!-- 创建 CustomerDaoImpl对象-->
   <bean id="customerDao" class="edu.xja.dao.impl.CustomerMySQLDaoImpl" scope="singleton" init-method="before" destroy-method="after"></bean>
</beans>

2.4.5 测试用例


class CustomerDaoTest {

    @Test
    @DisplayName("customerDao接口测试类")
    void save() {
        //1. 新建上下文环境,初始化SpringIOC容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2. 从容器中获取对象
        CustomerDao customerDao =(CustomerDao) applicationContext.getBean("customerDao");
        //3. 断言取出的对象不为空
        Assertions.assertTrue(customerDao!=null);
        //4. 调用对象方法
        customerDao.save();
        //5. 关闭上下文环境
        ((ClassPathXmlApplicationContext)applicationContext).close();

    }
}

2.5 Spring重要接口

2.5.1 ApplicationContext接口

(1)概念
1. ApplicationContext是SpringFramework中Bean的管理者,为SpringFramework的诸多功能提供支撑作用
2. ApplicationContext隶属于org.springframework.context包
3. 一般在使用Spring的时候,需要先得到一个ApplicationContext对象,然后从该对象中获取我们配置的Bean对象

(2)功能

在这里插入图片描述

1. ApplicationContext接口继承众多接口,集众多接口功能与一身,为Spring的运行提供基本的功能支撑。
2. 根据程序设计的“单一职责原则”,其实每个较顶层接口都是“单一职责的”,只提供某一方面的功能,,而ApplicationContext接口继承了众多接口,相当于拥有了众多接口的功能
3. ApplicationContext是个BeanFactory,可以管理、装配bean,可以有父级BeanFactory实现Bean的层级管理(具体到这里来说它可以有父级的ApplicationContext,因为ApplicationContext本身就是一个BeanFactory。这在web项目中很有用,可以使每个Servlet具有其独立的context, 所有Servlet共享一个父级的context)
4. 它还是ListableBeanFactory 的子类,可以枚举出所管理的bean对象。
5. 它是一个ResourceLoader(资源加载器),可以加载资源文件;(比如下载xml文件,properties文件)
6. 可以管理一些Message实现国际化等功能;
7. 可以发布事件给注册的Listener(监听器),实现监听机制。
(3)ApplicationContext两个常用的实现类
1. ClassPathXmlApplicationContext: 使用类路径方式初始化ioc容器(推荐使用)
(1)类路径方式加载,默认在类路径的根目录下(也就是src目录下)
2. FileSystemApplicationContext:  使用文件系统径的方式初始化ioc容器
(1)绝对路径方式
(2)相对路径方式

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

在这里插入图片描述

2.5.2 BeanFactory系列接口

(1) BeanFactory 接口
1. public interface BeanFactory 是一个接口
2. BeanFactory 是 Spring 管理 Bean 的最顶层接口
3. 是一个 Bean 容器, 管理一系列的 bean,每一个 bean 使用一个String 类型的 name(或称之为id) 来唯一确定,这些 Bean 可以是 prototype(原型模式) 的或者 singleton(单例模式)的
4. Spring 提倡使用依赖注入(Dependency Injection) 的方式装配 Bean
5. BeanFactory从“configuration source”(配置资源)加载Bean(普通java对象)的定义,configuration source 可以是xml文件或者properties文件甚至是数据库
(2)ierarchicalBeanFactory 接口
1. public interface HierarchicalBeanFactory extends BeanFactory
2. HierarchicalBeanFactory是一个具有层级关系的Bean 工厂,拥有属性parentBeanFactory,它是 BeanFactory的子接口
3. 当获取 Bean对象时,如果当前BeanFactory中不存在对应的bean,则会访问其直接 parentBeanFactory 以尝试获取bean 对象
4. 当前的 BeanFactory 中 override(重写) 父级BeanFactory的同名bean(java普通对象·)

(3)ListableBeanFactory接口
1. public interface ListableBeanFactory extends BeanFactory
2. BeanFactory的子类,实现了枚举方法可以列举出当前BeanFactory中所有的bean对象而不必根据name一个一个的获取
3. ListableBeanFactory 对象还是一个HierarchicalBeanFactory则getBeanDefinitionNames()方法只会返回当前BeanFactory中的Bean对象而不会去父级BeanFactory中查询。

2.6 SpringIOC的配置

2.6.1 Scope属性

1. scope 就是用来配置 spring bean 的作用域,它标识 bean 的作用域
2. 默认情况下Spring2.0现在有五种类型的Bean。
(1)singleton(单例)
(2)non-singleton(也称 prototype原型)
(3)session(会话级别)
(4)request(请求级别)
(5)global session

3. Spring2.0对 Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类型,满足实际应用需求。
(1)singleton(单例模式) 作用域

在这里插入图片描述

1. singleton(单例模式) 作用域:一个bean的作用域设置为singleton,Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id(一般是bean的类名)与该bean定义相匹配,则只会返回bean的同一实例(堆内存地址相同)
2. 单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例
3. 这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。

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

(2)prototype(原型)作用域

在这里插入图片描述

1. prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的 getBean()方法)都会产生一个新的bean实例,相当与一个new的操作
2. Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问
3. 不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。
4. 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责
5. 

在这里插入图片描述

在这里插入图片描述

(3)request作用域
1. request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
2. request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置:在web应用的XML声明文件web.xml中增加下述ContextListener即可
  <listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>

在这里插入图片描述

(4)session作用域
session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session(会话)内有效
  <listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>

在这里插入图片描述

(5)global session作用域
1. global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义
2. Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。
3. 在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成标识session类型来使用
  <listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>

在这里插入图片描述

2.6.2 对象的生命周期方法

(1)概念
Spring为了满足开发者在执行某方法之前或者在结束某个任务之前需要操作的一些业务,则提供了init-method和destroy-method  这两个属性,这两个属性需要加载在bean节点中。

(2)实例

package edu.xja.dao;

public interface CustomerDao {

    void before();
    /**
     * 存储方法
     */
    void save();


    /**
     * 执行结束方法
     */
    void after();
}

package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;

public class CustomerMySQLDaoImpl implements CustomerDao {
    public void before() {
        System.out.println("开始执行");
    }

    public void save() {
        System.out.println("存储用户信息到mysql数据库");
    }

    public void after() {
        System.out.println("执行完毕");
    }
}

package edu.xja.dao;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import static org.junit.jupiter.api.Assertions.*;

class CustomerDaoTest {

    @Test
    @DisplayName("customerDao接口测试类")
    void save() {
        //1. 新建上下文环境,初始化SpringIOC容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2. 从容器中获取对象
        CustomerDao customerDao =(CustomerDao) applicationContext.getBean("customerDao");
        //3. 断言取出的对象不为空
        Assertions.assertTrue(customerDao!=null);
        //4. 调用对象方法
        customerDao.save();
        //5. 关闭上下文环境
        ((ClassPathXmlApplicationContext)applicationContext).close();
    }
}

2.6.7 @Qualifier注解

(1) 概念
1. 在CustomerServiceImpl注入CustomerDao同时使用@Autowired和@Qualifier指定注入的对象名称。
2. 因为@Autowired是根据类型来查找对象,扫描时发现同个类型有两个实现类对象,程序就会报错
(2)错误实例:不指定对象

dao接口

package edu.xja.dao;

public interface CustomerDao {

    void before();
    /**
     * 存储方法
     */
    void save();


    /**
     * 执行结束方法
     */
    void after();
}

package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;
import org.springframework.stereotype.Repository;

@Repository(value="cuatomerDao1")
public class CustomerMySQLDaoImpl implements CustomerDao {
    public void before() {
        System.out.println("开始执行");
    }

    public void save() {
        System.out.println("存储用户信息到mysql数据库");
    }

    public void after() {
        System.out.println("执行完毕");
    }
}

dao实现类1

package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;
import org.springframework.stereotype.Repository;

@Repository(value="cuatomerDao2")
public class CustomerOracleDaoImpl implements CustomerDao {
    public void before() {
        System.out.println("开始执行");
    }

    public void save() {
        System.out.println("存储用户信息到mysql数据库");
    }

    public void after() {
        System.out.println("执行完毕");
    }

}

dao实现类2

package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;
import org.springframework.stereotype.Repository;

@Repository(value="cuatomerDao2")
public class CustomerOracleDaoImpl implements CustomerDao {
    public void before() {
        System.out.println("开始执行");
    }

    public void save() {
        System.out.println("存储用户信息到mysql数据库");
    }

    public void after() {
        System.out.println("执行完毕");
    }

}

service接口

package edu.xja.service;

public interface CustomerService {
    void save();
}

service接口实现类

package edu.xja.service.impl;

import edu.xja.dao.CustomerDao;
import edu.xja.dao.impl.CustomerMySQLDaoImpl;
import edu.xja.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service(value="customerService")
public class CustomerServiceImpl implements CustomerService {
    //@Autowired自动装配CustomerDao对象
    //此时没有指定对象,仅仅指定类型为CustomerDao 
    @Autowired
    private CustomerDao customerDao;

    public CustomerServiceImpl() {
    }

    public CustomerServiceImpl(CustomerDao customerDao) {
        this.customerDao = customerDao;
    }

    public CustomerDao getCustomerDao() {
        return customerDao;
    }

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


    /**
     * service层方法,调用dao层方法
     */
    public void save() {
       customerDao.save();
    }
}

service单元测试

package edu.xja.service.impl;
import edu.xja.service.CustomerService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

class CustomerServiceImplTest {

    @Test
    @DisplayName("测试依赖注入service以及它依赖的dao接口")
    void save() {
        //1.获取上下文环境
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.获取customerService接口对象
        CustomerService customerService = (CustomerService) applicationContext.getBean("customerService");
        //3.调用Service方法,不需要获取dao对象,容器里已经用构造方法注入dao对象了(或者setting方法注入了对象)
        customerService.save();
        //4.关闭上下文环境(需要强制类型转换到原本类型)
        ((ClassPathXmlApplicationContext)applicationContext).close();
    }
}

在这里插入图片描述

(3)正确实例:使用@Autowired和@Qualifier指定注入的对象名称
在属性上添加@Autowired表示对象
@Qualifier限制对象的类型
package edu.xja.service.impl;

import edu.xja.dao.CustomerDao;
import edu.xja.dao.impl.CustomerMySQLDaoImpl;
import edu.xja.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service(value="customerService")
public class CustomerServiceImpl implements CustomerService {
    //@Autowired自动装配CustomerDao对象
    //@Qualifier使用指定对象,值为指定对象的@Repository值
    @Autowired
    @Qualifier("cuatomerDao2")
    private CustomerDao customerDao;

    public CustomerServiceImpl() {
    }

    public CustomerServiceImpl(CustomerDao customerDao) {
        this.customerDao = customerDao;
    }

    public CustomerDao getCustomerDao() {
        return customerDao;
    }

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


    /**
     * service层方法,调用dao层方法
     */
    public void save() {
       customerDao.save();
    }
}

在这里插入图片描述

2.6.8 @Resource装配对象

1. @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上
2. @Autowired默认按类型装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) 
3. @Autowired想使用名称装配可以结合@Qualifier注解进行使用


4. @Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,
5. 如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找
6. 如果注解写在setter方法上默认取属性名进行装配
7. 当找不到与名称匹配的bean时@Resource(按照类型进行装配。
8. 如果name属性一旦指定,@Resource就只会按照名称进行装配。
9. @Resource(name="customerDao")     
private CustomerDao customerDao; 
package edu.xja.service.impl;

import edu.xja.dao.CustomerDao;
import edu.xja.dao.impl.CustomerMySQLDaoImpl;
import edu.xja.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service(value="customerService")
public class CustomerServiceImpl implements CustomerService {
    //@Resource注解name属性指定对象名称
    @Resource(name="customerDao1")
    private CustomerDao customerDao;

    public CustomerServiceImpl() {
    }

    public CustomerServiceImpl(CustomerDao customerDao) {
        this.customerDao = customerDao;
    }

    public CustomerDao getCustomerDao() {
        return customerDao;
    }

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


    /**
     * service层方法,调用dao层方法
     */
    public void save() {
       customerDao.save();
    }
}


在这里插入图片描述

2.7 零配置

零配置是不存在properties配置文件
使用加注解的类来创建applicatioContext应用上下文环境
主要用到注解:
(1)@Configuration 配置spring容器(应用上下文)
(2)@ComponentScan :扫描指定包名,查找依赖对象
(3)@PropertySource:加载properties文件
(4)@Import:加载另一个配置类JdbcConfig
(5)@Bean:把方法的返回结果放入IOC容器中,并且起个bean的id名称。

2.7.1 零配置-@Configuration

@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans>,作用为:配置spring容器(应用上下文)。
(1)编写SpringConfig作为Spring环境启动类
package edu.xja.util;

import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
        //构造方法
        public SpringConfig(){
            System.out.println("Spring环境初始化成功!");
        }
}

(2)编写测试类
package edu.xja.service;

import edu.xja.dao.CustomerDao;
import edu.xja.util.SpringConfig;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


class ServiceDaoTest {

    private Object Assertions;

    @Test
    void save() {
        //1.初始化Spring上下文环境
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
    }
}

在这里插入图片描述

2.7.2 零配置-@ComponentScan

@ComponentScan注解代替XML配置方式的<context:component-scan/>标签的作用。用于开启SpringIOC的注解扫描。
(1)编写接口和实现类

dao接口

package edu.xja.dao;

public interface CustomerDao {

    void before();
    /**
     * 存储方法
     */
    void save();


    /**
     * 执行结束方法
     */
    void after();
}

package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;
import org.springframework.stereotype.Repository;

@Repository(value="cuatomerDao1")
public class CustomerMySQLDaoImpl implements CustomerDao {
    public void before() {
        System.out.println("开始执行");
    }

    public void save() {
        System.out.println("存储用户信息到mysql数据库");
    }

    public void after() {
        System.out.println("执行完毕");
    }
}

dao实现类1

package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;
import org.springframework.stereotype.Repository;

@Repository(value="cuatomerDao2")
public class CustomerOracleDaoImpl implements CustomerDao {
    public void before() {
        System.out.println("开始执行");
    }

    public void save() {
        System.out.println("存储用户信息到mysql数据库");
    }

    public void after() {
        System.out.println("执行完毕");
    }

}

dao实现类2

package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;
import org.springframework.stereotype.Repository;

@Repository(value="cuatomerDao2")
public class CustomerOracleDaoImpl implements CustomerDao {
    public void before() {
        System.out.println("开始执行");
    }

    public void save() {
        System.out.println("存储用户信息到mysql数据库");
    }

    public void after() {
        System.out.println("执行完毕");
    }

}

service接口

package edu.xja.service;

public interface CustomerService {
    void save();
}

service接口实现类

package edu.xja.service.impl;

import edu.xja.dao.CustomerDao;
import edu.xja.dao.impl.CustomerMySQLDaoImpl;
import edu.xja.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service(value="customerService")
public class CustomerServiceImpl implements CustomerService {
    //@Autowired自动装配CustomerDao对象
    //此时没有指定对象,仅仅指定类型为CustomerDao 
    @Autowired
    private CustomerDao customerDao;

    public CustomerServiceImpl() {
    }

    public CustomerServiceImpl(CustomerDao customerDao) {
        this.customerDao = customerDao;
    }

    public CustomerDao getCustomerDao() {
        return customerDao;
    }

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


    /**
     * service层方法,调用dao层方法
     */
    public void save() {
       customerDao.save();
    }
}

(2)编写SpringConfig作为Spring环境启动类
package edu.xja.util;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration  //环境上下文
@ComponentScan(basePackages={"edu.xja"})   //basePackages属性可以加多个扫描包
public class SpringConfig {
        //构造方法
        public SpringConfig(){
            System.out.println("Spring环境初始化成功!");
        }
}

(3)测试类
package edu.xja.service;

import edu.xja.dao.CustomerDao;
import edu.xja.util.SpringConfig;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


class ServiceDaoTest {

    private Object Assertions;

    @Test
    void save() {
        //1.初始化Spring上下文环境
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        CustomerDao  customDao = (CustomerDao) applicationContext.getBean("customerDao1");
        customDao.save();
    }
}

在这里插入图片描述

2.7.3 零配置 @PropertySource

@PropertySource注解,用于代替<context:property-placeholader/>配置,加载properties配置文件。
(1)编写Dao接口和实现类
package edu.xja.dao;

public interface CustomerDao {
    public void save();
}
package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

@Repository(value="customerDao")
public class CustomerDaoImpl implements CustomerDao {
    //用注解为属性赋值
    @Value("${jdbcUrl}")
    private String jdbcUrl;
    
    @Value("${driverClass}")
    private String  driverClass;
    
    @Value("${user}")
    private String user;

    @Value("${passWord}")
    private String passWord;
    
    public void before() {
        
    }

    public void save() {

    }

    public void after() {

    }

    @Override
    public String toString() {
        return "CustomerDaoImpl{" +
                "jdbcUrl='" + jdbcUrl + '\'' +
                ", driverClass='" + driverClass + '\'' +
                ", user='" + user + '\'' +
                ", passWord='" + passWord + '\'' +
                '}';
    }
}

```
#### (2)新建jdbc.propertiesdbc.properties
```java
jdbcUrl=jdbc:mysql:///spring
driverClass=com.mysql.jdbc.Driver
user=root
password=zx200061
```

#### (3SpringConfig启动类
```java
package edu.xja.util;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration  //环境上下文
@ComponentScan(basePackages={"edu.xja"})   //basePackages属性可以加多个扫描包
@PropertySource(value="classpath:jdbc.properties")  //加载jdbc.properties文件
public class SpringConfig {
        //构造方法
        public SpringConfig(){
            System.out.println("Spring环境初始化成功!");
        }
}

```
### (4)测试方法
```java
package edu.xja.service;

import edu.xja.dao.CustomerDao;
import edu.xja.util.SpringConfig;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


class ServiceDaoTest {

    private Object Assertions;

    @Test
    void save() {
        //1.初始化Spring上下文环境,利用注解配置应用上下文获取上下文环境
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        //2. 获取依赖对象
        CustomerDao  customDao = (CustomerDao) applicationContext.getBean("customerDao1");
        //3. 调用依赖对象方法 
        customDao.save();
    }
}
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/cce23002f6914ae5ad8e89a7b73bb8cc.png)
### 2.7.4 -@Import
```
SpringConfig类中用了@Import注解,目的是加载另一个配置类JdbcConfig,这样可以实现同时使用多个配置类(类似于XML方式的多个applicationContext.xml)
```
#### (1)新建JdbcConfig配置类
```java
package edu.xja.util;
import org.springframework.context.annotation.PropertySource;

@PropertySource(value="classpath:jdbc.properties")//加载jdbc.properties文件
public class JdbcConfig {
    
}

```

####   (2SpringConfig启动类
```java
package edu.xja.util;

@Configuration  //环境上下文
@ComponentScan(basePackages={"edu.xja"})   //basePackages属性可以加多个扫描包
@Import(JdbcConfig.class)   //导入JdbcConfig配置类class文件
public class SpringConfig {

}

```
####   (3)测试类
```java
class ServiceDaoTest {

    private Object Assertions;

    @Test
    void save() {
        //1.初始化Spring上下文环境,利用注解配置应用上下文获取上下文环境
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        //2. 获取依赖对象
        CustomerDao  customDao = (CustomerDao) applicationContext.getBean("customerDao");
        //3. 调用依赖对象方法
        customDao.save();
    }
}

```
![在这里插入图片描述](https://img-blog.csdnimg.cn/cafa56bf0c3c42469b2f330bec0049d9.png)
```
测试通过
```
### 2.7.5 零配置-@Bean
```
1. @Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里。作用是,把方法的返回结果放入IOC容器中,并且起个bean的id名称。
2. @Bean@Component的区别?
(1@Component注解的作用是创建一个对象,放入IOC容器中。
(2@Bean注解并没有创建对象的能力,它只是获取某个方法的返回值,放入IOC容器中。
```

#### (2)编写接口和实现类
```java
public interface CustomerDao {
    public void save();
}
```

```java
import edu.xja.dao.CustomerDao;
import org.springframework.stereotype.Repository;

@Repository(value="customerDao")
public class CustomerDaoImpl implements CustomerDao {

   @Override
   public void save() {
      System.out.println("执行了CustomerDaoImpl的save()方法");
   }

}
```
#### (3SpringConfig启动类

```java
package edu.xja.util;

import edu.xja.dao.CustomerDao;
import edu.xja.dao.impl.CustomerDaoImpl;
import org.springframework.context.annotation.*;

@Configuration  //环境上下文
@ComponentScan(basePackages={"edu.xja"})   //basePackages属性可以加多个扫描包
public class SpringConfig {
    @Bean(name="customerDao") //获取getCustomerDao的返回对象,放入IOC容器中,并且起名为customerDao
    public CustomerDao getCustomerDao(){
        return new CustomerDaoImpl();
    }
}

```
```
在这里@Bean的作用,获取getCustomerDao的返回对象,放入IOC容器中,并且起名为customerDao。
```

#### (4)测试类
```java

class ServiceDaoTest {

    private Object Assertions;

    @Test
    void save() {
        //1.初始化Spring上下文环境,利用注解配置应用上下文获取上下文环境
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        //2. 获取依赖对象
        CustomerDao  customDao = (CustomerDao) applicationContext.getBean("customerDao");
        //3. 调用依赖对象方法
        customDao.save();
    }
}
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/5cba2a3d0e264a0d87ca418abb57e024.png)
## 2.8 Spring 整合Junit
### 2.8.1 为什么需要整合
```
1. 在开发基于Spring框架的项目时,发现通过Spring进行对象管理之后,做测试变得复杂了。因为所有的Bean都需要在applicationContext.xml中加载好,之后再通过@Resource去取得。如果每次都要整个业务流做的差不多了再去测试,这样效率很低

2. 其实Spring有一个测试框架,能够整合JUnit进行测试。

```

### 2.8.2 使用Spring-Test整合Junit简化测试
#### (1)引入spring-test测试依赖
```xml
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.3</version>
    <scope>test</scope>
</dependency>
```

#### (2)编写Dao接口和实现类
```java
package edu.xja.dao;

public interface CustomerDao {

    void before();
    /**
     * 存储方法
     */
    void save();


    /**
     * 执行结束方法
     */
    void after();
}

```
```java
package edu.xja.dao.impl;

import edu.xja.dao.CustomerDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

@Repository(value="customerDao")
public class CustomerDaoImpl implements CustomerDao {
    public void before() {

    }

    public void save() {
        System.out.println("执行了CustomerDaoImpl的save()方法");
    }

    public void after() {

    }
}

```
#### (3)resources下新增applicationContext.xml配置文件
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       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">

    <!-- 开启SpringIOC注解扫描 -->
    <context:component-scan base-package="edu.xja.dao"></context:component-scan>

</beans>

```
#### (4)编写Spring-Test整合Junit的测试类
```java

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值