一篇文章带你掌握主流基础框架-Spring

这篇文章中我们将会介绍Spring的框架以及本体内容,包括核心容器,注解开发,AOP以及事务等内容

那么简单说明一下Spring的必要性:

Spring的核心内容:

Spring可进行的框架整合:

在接下来的文章中,我们会学习Spring的框架思想,学习Spring的基本操作,结合案例熟练掌握

温馨提醒:在学习本篇文章前请先学习JavaWeb相关内容

(HTTP,Tomcat,Servlet,Request,Response,MVC,Cookie,Session,Ajax,Vue等内容)

初识Spring

官网:Spring | Home

Spring发展至今已经形成了一套开发的生态圈,Spring提供了相当多的项目,每个项目用于完成特定功能

我们常用的主流技术包括有:

Spring FrameWork系统架构

在系统学习Spring之前,我们需要先来了解FrameWork系统结构

我们现在所使用的Spring FrameWork是4.0版本,已经趋于稳定

下面我们对架构图进行解释:

我们可以在官方中获得如此评价:

核心概念介绍

首先我们思索一下我们之前的业务层与数据层:

// 数据层接口
public interface BookDao {
    public void save();
}
// 数据层实现
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
// 业务层接口
public interface BookService {
    public void save();
}
// 业务层实现
public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void save() {
        bookDao.save();
    }

}

如果我们修改BookDaoImpl内容,那么相对应的业务层实现中的bookDao的new实现也要进行修改,甚至下方方法的对象也要进行修改

Spring使用前问题

代码书写现状:

解放方案:

Spring思想以及实现

IoC(Inversion of Control)控制反转思想:

DI(Dependency Injection)依赖注入:

Spring技术对Ioc思想进行了实现:

// 数据层实现
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
// IoC容器
/*
包含
dao
service
两者可以建立连接
*/
// 业务层实现
public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void save() {
        bookDao.save();
    }

}

目的:充分解耦

最终效果:

IoC入门

首先我们需要明白IoC的使用规则:

  1. IoC负责管理什么:Service和Dao
  2. 如何被管理的对象告知IoC容器:(配置)
  3. 被管理的对象交给IoC容器,如何获得IoC容器:(接口)
  4. IoC容器得到之后,如何获得Bean:(接口方法)
  5. 使用Spring所需要导入的坐标:(pom.xml)

下面我们给出IoC入门的详细步骤:

  1. 创建Maven项目,在pom.xml中导入坐标
  
    
      org.springframework
      spring-context
      5.2.10.RELEASE
    
  
  1. 创建Spring.xml的配置包(applicationContext.xml,导入坐标后xml中更新该XML)
<?xml version="1.0" encoding="UTF-8"?>


    
    
    
    

    


  1. 主函数
package com.itheima;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        //3.获取IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        //4.获取bean(根据bean配置id获取)
		//BookDao bookDao = (BookDao) ctx.getBean("bookDao");
		//bookDao.save();
        
        // 注意:需要类型转化

        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();

    }
}

DI入门

首先我们需要明白DI的使用规则:

  1. 基于IoC管理bean
  2. Service中使用new形式创建Dao对象是否保留:(否)
  3. Service中需要Dao对象如何进入到Service中:(提供方法)
  4. Service与Dao之间的关系如何描述:(配置)

下面我们给出DI入门的详细步骤(基于IoC入门):

  1. 删除new方法
public class BookServiceImpl implements BookService {
    //5.删除业务层中使用new的方式创建的dao对象
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

}
  1. 创建对象的set方法
public class BookServiceImpl implements BookService {
    //5.删除业务层中使用new的方式创建的dao对象
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
    
    //6.提供对应的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}
  1. 创建Dao和Service的连接
<?xml version="1.0" encoding="UTF-8"?>


    
    
    

    
        
        
        
    


Bean整体介绍

Bean是保存在IoC中的对象,我们通过配置的方式获得Bean

下面我们从三个方面分别讲解Bean:

bean基本配置

首先我们先介绍bean本身性质:

类别

描述

名称

bean

类型

标签

所属

beans标签

功能

定义Spring核心容器管理对象

格式



属性列表

id:bean的id,使用容器可以通过id值获得对应的bean,在一个容器中id值唯一
class:bean的类型,即配置的bean的全路径类名

范例

然后我们介绍一下bean的别名:

类别

描述

名称

name

类型

标签

所属

bean标签

功能

定义bean的别名,可定义多个,使用逗号,分号,空格分隔

范例

正常情况下,使用id和name都可以获得bean,但推荐还是使用唯一id

获得bean无论通过id还是name获取,如果无法找到则抛出异常NosuchBeanDefinitionException

最后我们介绍一下bean的作用范围scope:

类别

描述

名称

scope

类型

标签

所属

bean标签

功能

定义bean的作用范围,可选范围如下:
singleton:单列(默认)
prototype:非单列

范例

这里的scope指产生对象的数量

我们的scope在默认情况下是singleton,因为很多对象只需要创建一次,多次创建会导致内存膨胀

合适交给容器进行管理的bean(singleton):

表现层对象业务层对象数据层对象工具对象

不合适交给容器进行管理的bean(prototype):

封装实体的域对象(带有状态的bean)

bean实例化

bean的实例化通常分为四种方法,我们在下面一一介绍:

  1. 构造方法(常用)

我们需要在数据类中提供构造方法,配置条件中不需要改变

// 数据类

public class BookDaoImpl implements BookDao {

    public BookDaoImpl() {
        System.out.println("book dao constructor is running ....");
    }

    public void save() {
        System.out.println("book dao save ...");
    }

}
<?xml version="1.0" encoding="UTF-8"?>


    
    


若无参构造方法不存在,则抛出异常BeanCreationException

  1. 静态工厂(了解)

我们在之前的案例中存在有对象工厂的说法,我们可以设置工厂并调用其方法得到bean

// 静态工厂
package com.itheima.factory;

import com.itheima.dao.OrderDao;
import com.itheima.dao.impl.OrderDaoImpl;
//静态工厂创建对象
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("factory setup....");
        return new OrderDaoImpl();
    }
}
<?xml version="1.0" encoding="UTF-8"?>


    
    


  1. 实例工厂(了解)

和静态工厂相同,但不同点是方法不是静态,我们需要提前创建一个bean

// 实例工厂
package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
//实例工厂创建对象
public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

<?xml version="1.0" encoding="UTF-8"?>

    
    

    
    


  1. FactoryBean(重要实用)

除了我们之前自己定义的工厂外,Spring提供了一种官方版本的FactoryBean

// FactoryBean工厂(需接口,< >中填写数据类接口)
package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;
//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean {
    //代替原始实例工厂中创建对象的方法
    
    // 返回创建对象类型为UserDaoImpl()
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    // 这里填写接口类型
    public Class<?> getObjectType() {
        return UserDao.class;
    }

    // 可以修改来修改其scope属性
    public boolean isSingleton() {
        return false;
    }
}
<?xml version="1.0" encoding="UTF-8"?>


    
    


bean生命周期

我们先来接单介绍生命周期相关概念:

接下来我们介绍生命周期控制方法:

  1. 数据层提供控制方法

由数据层提供方法,在xml配置文件中设置该方法

// 数据层
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    
    public void save() {
        System.out.println("book dao save ...");
    }
    
    //表示bean初始化对应的操作
    public void init(){
        System.out.println("init...");
    }
    //表示bean销毁前对应的操作
    public void destory(){
        System.out.println("destory...");
    }

}


<?xml version="1.0" encoding="UTF-8"?>


    
    
    

    
        
    


  1. 接口控制方法(了解)

Spring为创建提供了两个接口,我们只需要继承并实现该方法即可

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

// InitializingBean,DisposableBean 分别对应afterPropertiesSet,destroy方法,代表创建和销毁
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        System.out.println("set .....");
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

    public void destroy() throws Exception {
        System.out.println("service destroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }
}

<?xml version="1.0" encoding="UTF-8"?>


    
    
    
    
        
    



我们需要提及一下bean的销毁时机:(了解即可)

所以如果我们希望销毁bean观察到destroy的实现,需要手动关闭:

  1. 手动关闭容器方法:
package com.itheima;

import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForLifeCycle {
    public static void main( String[] args ) {
        // 注意:这里需要采用ClassPathXmlApplicationContext作为对象,因为只有这个类才具有close方法
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        //关闭容器
        ctx.close();
    }
}

  1. 注册关闭钩子,在虚拟机退出前先关闭容器再推出虚拟机
package com.itheima;

import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForLifeCycle {
    public static void main( String[] args ) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
        ctx.registerShutdownHook();
    }
}

最后我们统计一下整体生命周期:

初始化容器:创建对象(分配内存)->执行构造方法->执行属性注入(set操作)->执行bean初始化方法使用bean:执行业务操作关闭/销毁容器:执行bean销毁方法

依赖注入方式

首先我们要知道类中传递数据的方法有两种:

然后我们要知道数据的类型大体分为两种:

所以我们把依赖注入方式分为四种:

setter注入简单类型

首先我们需要在bean种定义简单类型属性并提供可以访问的set方法

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {

    private String databaseName;
    private int connectionNum;
    //setter注入需要提供要注入对象的set方法
    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }
    //setter注入需要提供要注入对象的set方法
    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }

    public void save() {
        System.out.println("book dao save ..."+databaseName+","+connectionNum);
    }
}

然后在配置中使用property标签value属性注入简单类型数据

<?xml version="1.0" encoding="UTF-8"?>


    
    
        
        
        
        
        
    



setter注入引用类型

首先我们需要在bean种定义引用类型属性并提供可以访问的set方法

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.UserDao;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService{
    private BookDao bookDao;
    private UserDao userDao;
    //setter注入需要提供要注入对象的set方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    //setter注入需要提供要注入对象的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
        userDao.save();
    }
}

然后在配置中使用property标签ref属性注入引用类型数据

<?xml version="1.0" encoding="UTF-8"?>


    
        
        
    

    

    
    
        
        
        
        
        
    


构造器注入简单类型(了解)

在bean中定义简单类型属性并提供可访问的set方法

public class BookDaoImpl implements BookDao{
	private int connectionNumber;
    
    pubilc void setConnectionNumber(int connectionNumber){
		this.connectionNumber = connectionNumber;
    }
}

配置中使用constructor-arg标签value属性注入简单类型数据

<?xml version="1.0" encoding="UTF-8"?>


    
        根据构造方法参数名称注入
        
    
    



构造器注入引用类型(了解)

在bean中定义引用类型属性并提供可访问的构造方法

public class BookDaoImpl implements BookDao{
	private BookBao bookBao;
    
    pubilc void setConnectionNumber(int connectionNumber){
		this.bookBao = bookBao;
    }
}

配置中使用constructor-arg标签ref属性注入简单类型数据

<?xml version="1.0" encoding="UTF-8"?>


    
        
        
    



构造器注入参数配置问题(了解)

在前面我们已经介绍了构造器的注入方法

但如果我们在bean中的数据名称发生改变,配置就不再适配,所以提供了一些方法来解决参数配置问题:

	
    
        根据构造方法参数类型注入
        
        
    
    

    
        
        
    

    
    
        
        
        
    
    

    
        
        
    

依赖注入方式选择

依赖注入方式有以下选择标准:

  1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
  2. 可选依赖使用setter注入进行,灵活性高
  3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
  4. 如果有必要可以两者并用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
  5. 实际开发中根据情况分析,如果受控对象没有提供setter方法则只能采用构造器注入
  6. 自己开发的模块尽量推荐setter注入

依赖自动装配

在前面我们学习了手动注入的方法,但Spring其实为我们提供了一种依赖自动装配的语法:

自动装配方式:

自动装配语法:

<?xml version="1.0" encoding="UTF-8"?>


    
    
    


依赖自动装配特征:

自动装配用于引用类型注入,不能对简单类型进行操作使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用自动装配优先级低于setter注入和构造器注入,同时出现时,自动装配配置失效

依赖集合注入

除了基本类型和引入类型外,我们有时也需要注入集合

下面我们简单介绍一下结合的注入:

// 数据类 

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

import java.util.*;

public class BookDaoImpl implements BookDao {

    private int[] array;

    private List list;

    private Set set;

    private Map map;

    private Properties properties;




    public void setArray(int[] array) {
        this.array = array;
    }

    public void setList(List list) {
        this.list = list;
    }

    public void setSet(Set set) {
        this.set = set;
    }

    public void setMap(Map map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }




    public void save() {
        System.out.println("book dao save ...");

        System.out.println("遍历数组:" + Arrays.toString(array));

        System.out.println("遍历List" + list);

        System.out.println("遍历Set" + set);

        System.out.println("遍历Map" + map);

        System.out.println("遍历Properties" + properties);
    }
}



<?xml version="1.0" encoding="UTF-8"?>

    
        
        
        
            
                100
                200
                300
            
        
        
        
            
                itcast
                itheima
                boxuegu
                chuanzhihui
            
        
        
        
            
                itcast
                itheima
                boxuegu
                boxuegu
            
        
        
        
            
                
                
                
            
        
        
        
            
                china
                henan
                kaifeng
            
        
    


案例:数据源对象管理

针对一个新的数据源对象,我们采用两步来创建bean(我们以druid为案例):

<?xml version="1.0" encoding="UTF-8"?>

    4.0.0

    com.itheima
    spring_09_datasource
    1.0-SNAPSHOT

    
        
            org.springframework
            spring-context
            5.2.10.RELEASE
        
        
        
            com.alibaba
            druid
            1.1.16
        
        
            mysql
            mysql-connector-java
            5.1.47
        
    

<?xml version="1.0" encoding="UTF-8"?>

    

    
    
        
        
        
        
        
    


案例:加载properties文件

这个案例我们将会介绍如何加载properties文件,并将文件带入到property基本信息中

我们大致将步骤分为以下三步:

<?xml version="1.0" encoding="UTF-8"?>









    
        
        
        
        
    

除了上述的基本操作,我们在context命名空间的使用中有很多需要注意的点:








 


核心容器

前面已经完成bean与依赖注入的相关知识学习,接下来我们主要学习的是IOC容器中的核心容器。

这里所说的核心容器,大家可以把它简单的理解为ApplicationContext,接下来我们从以下几个问题入手来学习下容器的相关知识:

容器的创建方式

案例中创建ApplicationContext的方式为(类路径下的XML配置文件):

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

除了上面这种方式,Spring还提供了另外一种创建方式为(文件的绝对路径):

ApplicationContext ctx = new FileSystemXmlApplicationContext("D:workspacespringspring_10_containersrcmainresourcesapplicationContext.xml");

Bean的三种获取方式

方式一,就是目前案例中获取的方式:

BookDao bookDao = (BookDao) ctx.getBean("bookDao");

这种方式存在的问题是每次获取的时候都需要进行类型转换

方式二:

BookDao bookDao = ctx.getBean("bookDao",BookDao.class);

这种方式可以解决类型强转问题,但是参数又多加了一个,相对来说没有简化多少。

方式三:

BookDao bookDao = ctx.getBean(BookDao.class);

这种方式就类似我们之前所学习依赖注入中的按类型注入。必须要确保IOC容器中该类型对应的bean对象只能有一个。

容器类层次结构

下面我们给出容器的层次图

BeanFactory的使用

使用BeanFactory来创建IOC容器的具体实现方式为:

public class AppForBeanFactory {
    public static void main(String[] args) {
        Resource resources = new ClassPathResource("applicationContext.xml");
        BeanFactory bf = new XmlBeanFactory(resources);
        BookDao bookDao = bf.getBean(BookDao.class);
        bookDao.save();
    }
}

为了更好的看出BeanFactory和ApplicationContext之间的区别,在BookDaoImpl添加如下构造函数:

public class BookDaoImpl implements BookDao {
    public BookDaoImpl() {
        System.out.println("constructor");
    }
    public void save() {
        System.out.println("book dao save ..." );
    }
}

如果不去获取bean对象,打印会发现:

核心概念总结

接下来我们对前面知识的一个总结,共包含如下内容:

容器相关

bean相关

依赖注入相关

注解开发

在上述的开发中,我们采用xml配置文件的形式来说依旧显得有些复杂

这时我们就需要发挥Spring的优点:简化开发,通过注解来简化开发过程

下面我们会通过多个方面将Bean逐步转化为注解

注解开发Bean

在前面的内容中,我们的bean在xml配置文件中装配

<?xml version="1.0" encoding="UTF-8"?>

    
    
    
    

在后期,我们的bean可以采用注解的形式,直接在实现类中注解表示为bean

我们采用@Component定义bean,可以添加参数表示id,也可以不添加参数,后期我们采用class类的类型来进行匹配

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;

//@Component定义bean
@Component("bookDao")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

//@Component定义bean
@Component
public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

@Componenty延伸出了三种类型,在实现手法上是一致,但可以具体使用于各种类中(仅用于自我识别)

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
//@Component定义bean
//@Component("bookDao")
//@Repository:@Component衍生注解
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
//@Component定义bean
//@Component
//@Service:@Component衍生注解
@Service
public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

但是,在上述情况下,即使我们将@Component的类定义为bean

我们的xml文件是无法探测到的,所以我们需要配置相关扫描组件来扫描bean

<?xml version="1.0" encoding="UTF-8"?>


    
    
    


纯注解开发

我们前面所提到的注解开发属于2.5的附属版本

在Spring3.0版本,Spring就提供了纯注解开发模式,利用java类代替配置文件,开启了Spring快速开发时代

在之前我们的xml配置文件是很繁琐的:



<?xml version="1.0" encoding="UTF-8"?>

    
    
    
    

但是我们可以通过创建单独的类来表示配置文件:

package com.itheima.config;

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

//声明当前类为Spring配置类
@Configuration
//设置bean扫描路径,多个路径书写为字符串数组格式
@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig {
}

注意:因为该类属于配置类,我们通常单列一个文件夹来表示

常用文件夹:config

命名规范:SpringConfig,UserConfig...

因为我们的开发不再依靠于xml配置文件,所以在主函数中的Spring容器获得方式也发生了改变:

package com.itheima;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        
        // 这是我们之前的获取方式,采用路径获取xml文件
        // ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        // 这是新的获取方式,直接提供配置类的类型
        // AnnotationConfigApplicationContext加载Spring配置类初始化Spring容器
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        
        // 后面操作无需变化
        
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        System.out.println(bookDao);
        //按类型获取bean
        BookService bookService = ctx.getBean(BookService.class);
        System.out.println(bookService);
    }
}

注解开发Bean作用范围与管理

既然我们的Bean开发从xml转移到注解开发,那么一些配置设置同样发生改变

首先我们介绍Scope范围的设置方式:

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Repository
//@Scope设置bean的作用范围(singleton或prototype),可以不添加默认singleton
@Scope("singleton")
public class BookDaoImpl implements BookDao {

    public void save() {
        System.out.println("book dao save ...");
    }

}

然后我们介绍一下bean生命周期的init和destroy操作:

依赖注入(自动装配)

在Spring3.0中,省略掉了前面繁琐的依赖注入,我们的bean依赖注入只留下了自动装配这一操作:

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class BookServiceImpl implements BookService {
    //@Autowired:注入引用类型,自动装配模式,默认按类型装配
    @Autowired
    //@Qualifier:自动装配bean时按bean名称装配
    @Qualifier("bookDao")
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

注意:自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法

注意:自动转配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法

注意:@Qualifier是基于@Autowired实现的,必须保证先有Autowired才能存在Qualifier

除了上述的bean类型装配,我们的简单类型装配依旧存在:

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    //@Value:注入简单类型(无需提供set方法)
    @Value("123")
    private String name;

    public void save() {
        System.out.println("book dao save ..." + name);
    }
}

之所以使用@Value的形式配置,是因为我们的类型值不一定是由手动输入的,有可能来自于Properties资源:

package com.itheima.config;

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

@Configuration
@ComponentScan("com.itheima")
//@PropertySource加载properties配置文件
@PropertySource({"jdbc.properties"})
public class SpringConfig {
}
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    //@Value:注入简单类型(无需提供set方法)
    @Value("${name}")
    private String name;

    public void save() {
        System.out.println("book dao save ..." + name);
    }
}

注解开发第三方bean

我们在实际开发中不仅仅需要对自己的bean进行管理,有时候可能需要引进其他的bean

下面我们以Druid为例进行讲解:

  1. 首先在pom.xml中导入Druid坐标
<?xml version="1.0" encoding="UTF-8"?>


  4.0.0

  com.itheima
  spring_14_annotation_third_bean_manager
  1.0-SNAPSHOT

  
    
      org.springframework
      spring-context
      5.2.10.RELEASE
    
    
      com.alibaba
      druid
      1.1.16
    
  


  1. 使用@Bean配置第三方Bean
// 该bean同样属于config文件,我们同样放置在config文件夹下
// 在后续我们将会讲解如何进行连接

package com.itheima.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

public class JdbcConfig {
    
    // 1.定义一个方法获得要管理的对象    
    // 2.添加@Bean,表示当前方法的返回值是一个bean
    // @Bean修饰的方法,形参根据类型自动装配
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }
}
  1. 将独立的配置类加入核心配置(导入法)
// SpringConfig

package com.itheima.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 org.springframework.context.annotation.Import;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com.itheima")
//@Import:导入配置信息(如果需要多个,同样采用{}数组形式)
@Import({JdbcConfig.class})
public class SpringConfig {
}

// JdbcConfig

package com.itheima.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

//@Configuration
public class JdbcConfig {
    //@Bean修饰的方法,形参根据类型自动装配
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
		// 配置信息
        return ds;
    }
}

注意:除了上述的导入法外还存在有其他方法,但导入法属于主流,因此我们不介绍其他流派,感兴趣的同学可以去查阅一下

注解开发为第三方导入资源

我们的第三方bean也可能需要导入部分资源,下面我们进行简单介绍:

package com.itheima.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

//@Configuration
public class JdbcConfig {
    
    //1.定义一个方法获得要管理的对象
    @Value("com.mysql.jdbc.Driver")
    private String driver;
    @Value("jdbc:mysql://localhost:3306/spring_db")
    private String url;
    @Value("root")
    private String userName;
    @Value("root")
    private String password;
    
    //2.添加@Bean,表示当前方法的返回值是一个bean
    //@Bean修饰的方法,形参根据类型自动装配
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }
}

package com.itheima.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

public class JdbcConfig {

    @Bean
    public DataSource dataSource(BookDao bookDao){
        // 我们只需要调用即可,系统会为我们自动装配
        System.out.println(bookDao);
    }
    
}

引入类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象

原文链接:https://www.cnblogs.com/qiuluoyuweiliang/p/16750470.html

展开阅读全文

页面更新:2024-04-18

标签:注解   容器   框架   属性   定义   对象   主流   类型   简单   方式   基础   方法   数据

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top