Spring学习总结(一)——Spring实现IoC的多种方式

一、Spring框架概述

Spring是一个开源免费的框架,为了解决企业应用开发的复杂性而创建。Spring框架是一个轻量级的解决方案,可以一站式地构建企业级应用。Spring是模块化的,所以可以只使用其中需要的部分。可以在任何web框架上使用控制反转(IoC),也可以只使用Hibernate集成代码或JDBC抽象层。它支持声明式事务管理、通过RMI或web服务实现远程访问,并可以使用多种方式持久化数据。它提供了功能全面的MVC框架,可以透明地集成AOP到软件中。

Spring被设计为非侵入式的,这意味着你的域逻辑代码通常不会依赖于框架本身。在集成层(比如数据访问层),会存在一些依赖同时依赖于数据访问技术和Spring,但是这些依赖可以很容易地从代码库中分离出来。

Spring框架是基于Java平台的,它为开发Java应用提供了全方位的基础设施支持,并且它很好地处理了这些基础设施,所以你只需要关注你的应用本身即可。

Spring可以使用POJO(普通的Java对象,plain old java objects)创建应用,并且可以将企业服务非侵入式地应用到POJO。这项功能适用于Java SE编程模型以及全部或部分的Java EE。

那么,做为开发者可以从Spring获得哪些好处呢?

不用关心事务API就可以执行数据库事务;

不用关心远程API就可以使用远程操作;

不用关心JMX API就可以进行管理操作;

不用关心JMS API就可以进行消息处理。

①JMX,Java Management eXtension,Java管理扩展,是一个为应用程序、设备、系统等植入管理功能的框架。JMX可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。

②JMS,Java Message Service,Java消息服务,是Java平台上有关面向消息中间件(MOM)的技术规范,它便于消息系统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。

一句话概括:Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

1.1、资源

官网: http://spring.io

文档: https://docs.spring.io/spring/docs/current/spring-framework-reference/、 https://github.com/waylau/spring-framework-4-reference

中文帮助: http://spring.cndocs.ml/

框架下载地址: http://repo.springsource.org/libs-release-local/org/springframework/spring/

教程: http://www.yiibai.com/spring

Git: https://github.com/spring-projects

源码: https://github.com/spring-projects/spring-framework

Jar包: https://github.com/spring-projects/spring-framework/releases

1.2、Spring历史

2002年,Rod Jahnson在《Expert One-on-One J2EE Design and Development》书中首次推出了Spring框架雏形interface21框架。

2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。

从2004年3月到现在,已经经历了1.0、1.1、1.2、2.0、2.5、3.0、3.1几个主要的版本

3.2.0版发布 2013年5月5日13:53 

3.2.10版发布 2014年7月15日23:58

3.2.9版发布 2014年5月20日12:22

4.0.0版发布 2013年12月12日07:50

4.0.1版发布 2014年1月28日20:55

4.1.6版发布 2015年3月25日16:40

4.2.2版发布 2015年10月15日12:57

4.2.5版发布 2016年2月25日09:28

4.3.5版发布 2016年12月21日11:34

4.3.6版发布 2017年1月25日14:05

4.3.8版发布 2017年4月18日13:49

4.3.9版发布 2017年6月7日19:29

5.0.0版发布 2017年9月28日11:28

5.0.1版发布 2017年10月24日15:14

1.3、框架特征与功能

轻量:从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

控制反转Ioc:Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

面向切面Aop:Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

容器:Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

框架:Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

MVC:Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架,Spring MVC是一个非常受欢迎的轻量级Web框架。

所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。

1.4、Spring组成

Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式

组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
  • Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
  • Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
  • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
  • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
  • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

Spring 框架的功能可以用在任何 J2EE 服务器中,大多数功能也适用于不受管理的环境。Spring 的核心要点是:支持不绑定到特定 J2EE 服务的可重用业务和数据访问对象。毫无疑问,这样的对象可以在不同 J2EE 环境 (Web 或 EJB)、独立应用程序、测试环境之间重用。

Spring是一个开源的框架,现在的Spring框架构成了一个体系平台,通过Spring的官方网站http://www.springsource.org可以了解到,围绕着Spring框架本身,还有许多其他优秀的项目:

SpringFramework(Core):核心项目

Spring Web Flow:工作流项目

Spring Security:安全项目

Spring Batch:批量数据处理项目

Spring Android:Android系统支持项目

Spring Social:社交项目

1.5、Spring Boot与Spring Cloud

Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的云应用开发工具;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。

SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。

二、IoC基础

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中我们使用面向对象编程对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

三、使用XML配置的方式实现IOC

假设项目中需要完成对图书的数据访问服务,我们定义好了IUserDao接口与UserDaoImpl实现类。

创建maven项目:

Spring学习总结(一)——Spring实现IoC的多种方式_第1张图片

IUserDao接口如下:

package cn.liuw.dao;

import cn.liuw.po.User;

/**
 * @ClassName IUserDao
 * @Description 用户数据访问接口
 **/
public interface IUserDao {
    /**
     * 添加图书
     */
    public void addUser(User user);
}

UserDaoImpl实现类如下:

package cn.liuw.dao.impl;

import cn.liuw.dao.IUserDao;
import cn.liuw.po.User;

/**
 * @ClassName UserDaoImpl
 * @Description TODO
 **/
public class UserDaoImpl implements IUserDao{
    @Override
    public void addUser(User user) {
        System.out.println(user);
    }
}

Maven项目的pom.xml如下:




  4.0.0

  cn.lv
  Learning-Spring
  1.0-SNAPSHOT
  war

  Learning-Spring Maven Webapp
  
  http://www.example.com

  
    UTF-8
    1.7
    1.7
    4.3.1.RELEASE
  

  
    
      junit
      junit
      4.12
      test
    
    
    
      log4j
      log4j
      1.2.16
    
    
    
      mysql
      mysql-connector-java
      5.1.35
    
    
    
      org.springframework
      spring-core
      ${spring.version}
    
    
      org.springframework
      spring-beans
      ${spring.version}
    
    
      org.springframework
      spring-context
      ${spring.version}
    
    
      org.springframework
      spring-tx
      ${spring.version}
    
    
      org.springframework
      spring-jdbc
      ${spring.version}
    
    
      org.springframework
      spring-orm
      ${spring.version}
    
    
      org.springframework
      spring-test
      ${spring.version}
      test
    
    
      org.springframework
      spring-expression
      ${spring.version}
    
    
      org.springframework
      spring-aop
      ${spring.version}
    
    
      org.aspectj
      aspectjweaver
      1.8.9
    
    
    
      commons-dbcp
      commons-dbcp
      1.2.2
    
  

  
    Learning-Spring
    
      
        
          maven-clean-plugin
          3.0.0
        
        
        
          maven-resources-plugin
          3.0.2
        
        
          maven-compiler-plugin
          3.7.0
        
        
          maven-surefire-plugin
          2.20.1
        
        
          maven-war-plugin
          3.2.0
        
        
          maven-install-plugin
          2.5.2
        
        
          maven-deploy-plugin
          2.8.2
        
      
    
  

业务接口IUserService如下:

package cn.liuw.service;

import cn.liuw.dao.IUserDao;
import cn.liuw.po.User;

/**
 * @ClassName IUserService
 * @Description TODO
 **/
public interface IUserService {
    public void saveUser(User user);
}

业务实现类UserServiceImpl如下:

package cn.liuw.service.impl;

import cn.liuw.dao.IUserDao;
import cn.liuw.po.User;
import cn.liuw.service.IUserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @ClassName UserServiceImpl
 * @Description TODO
 **/
public class UserServiceImpl implements IUserService{

    IUserDao userDao;

    public UserServiceImpl() {
        //容器
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        //从容器中获取id = userDao的bean
        userDao = (IUserDao) context.getBean("userDao");
    }

    @Override
    public void saveUser(User user) {
        System.out.println("开始添加用户...");
        userDao.addUser(user);
        System.out.println("结束添加用户...");
    }
}

 容器的配置文件applicationContext.xml如下:




    
    

测试类Test如下:

import cn.liuw.po.User;
import cn.liuw.service.IUserService;
import cn.liuw.service.impl.UserServiceImpl;
import org.junit.Test;

/**
 * @ClassName Test01
 * @Description TODO
 **/
public class Test01 {
    @Test
    public void testSaveUser(){
        //手动创建IUserService对象
        IUserService userService = new UserServiceImpl();
        //创建一个User对象进行保存
        User user = new User();
        user.setId(1);
        user.setUsername("张三");
        user.setSex("男");
        user.setAddress("石家庄裕华区");
        //这里使用applicationContext.xml的IOC管理userService对象中的userDao对象
        userService.saveUser(user);
    }
}

运行结果:

开始添加用户...
User{id=1, username='张三', sex='男', birthday=null, address='石家庄裕华区'}
结束添加用户...

Process finished with exit code 0

3.1、使用无参构造方法创建对象

如下所示,则上下文会使用无参构造方法创建对象




    
    

3.2、使用有参构造方法创建对象

Person.java

package cn.liuw.po;

/**
 * @ClassName Person
 * @Description TODO
 **/
public abstract class Person {
    String name;
}

Student.java

package cn.liuw.po;

/**
 * @ClassName Student
 * @Description TODO
 **/
public class Student extends Person{
    private int height;

    public Student(String name,int height) {
        this.name = name;
        this.height = height;
    }

    @Override
    public String toString() {
        return "Student{" +
                "height=" + height +
                ", name='" + name + '\'' +
                '}';
    }
}

测试类:

import cn.liuw.po.Person;
import cn.liuw.po.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @ClassName Test02
 * @Description TODO
 **/
public class Test02{
    public static void main(String[] args) {
        //IoC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从容器中获取对象
        Person person = context.getBean(Student.class);
        System.out.println(person);
    }
}

配置文件applicationContext.xml:




    
    
        
        
    

运行结果:

Student{height=180, name='小明'}

Process finished with exit code 0

注意:如果在使用构造方法时不想通过参数名称指定参数则可以直接使用索引,如:


    
    

3.3、通过属性赋值

Address地址类:

package cn.liuw.po;

/**
 * @ClassName Address
 * @Description TODO
 **/
public class Address {
    //国家
    private String country;
    //城市
    private String city;

    public Address(){
    }

    public Address(String country, String city) {
        this.country = country;
        this.city = city;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "Address{" +
                "country='" + country + '\'' +
                ", city='" + city + '\'' +
                '}';
    }
}

配置文件applicationContext.xml:




    
    
        
        
    

测试类:

import cn.liuw.po.Address;
import cn.liuw.po.Person;
import cn.liuw.po.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @ClassName Test02
 * @Description TODO
 **/
public class Test02{
    public static void main(String[] args) {
        //IoC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从容器中获取对象
        Address address = context.getBean(Address.class);
        System.out.println(address);
    }
}

运行结果:

Address{country='中国', city='石家庄'}

Process finished with exit code 0

3.5、对象作用域

使用scope属性可以指定作用域

配置文件applicationContext.xml:




	
	

测试类:

import cn.liuw.po.Address;
import cn.liuw.po.Person;
import cn.liuw.po.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @ClassName Test02
 * @Description TODO
 **/
public class Test02{
    public static void main(String[] args) {
        //IoC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从容器中获取对象
        Address addr1 = (Address) context.getBean("address2");
        Address addr2 = (Address) context.getBean("address2");
        //默认一个bean对应一个单例的对象,但是id=address2这个bean设置了属性scope=prototype
        System.out.println(addr1 == addr2);
    }
}

运行结果:

false

Process finished with exit code 0

3.6、延迟初始化bean

ApplicationContext实现的默认行为是在启动时将所有singleton bean提前进行实例化。 如果你不想这样,你可以将单例bean定义为延迟加载防止它提前实例化。延迟初始化bean会告诉IOC容器在第一次需要的时候再实例化而不是在容器启动时就实例化。

配置文件applicationContext.xml:


	
	

测试类:

import cn.liuw.po.Address;
import cn.liuw.po.Person;
import cn.liuw.po.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @ClassName Test02
 * @Description TODO
 **/
public class Test02{
    public static void main(String[] args) throws InterruptedException {
        //IoC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("+++++++++++++++++++++++++");
        //从容器中获取对象
        Address address = (Address) context.getBean("address3");
        System.out.println(address);
    }
}

运行结果:

+++++++++++++++++++++++++
初始化...
Address{country='中国', city='石家庄'}

我们看到打印的"初始化..."是在"+++++++"后面的,这说明,在加载applicationContext.xml的时候并未创建id=address3的bean。

四、使用Spring注解配置IOC

上一个示例是使用传统的xml配置完成IOC的,如果内容比较多则配置需花费很多时间,通过注解可以减轻工作量,但注解后修改要麻烦一些,耦合度会增加,应该根据需要选择合适的方法。

4.1 常用注解

修改上面的UserDaoImpl类,添加注解@Component:

package cn.liuw.dao.impl;

import cn.liuw.dao.IUserDao;
import cn.liuw.po.User;
import org.springframework.stereotype.Component;

/**
 * @ClassName UserDaoImpl
 * @Description TODO
 **/
@Component("userDao")
public class UserDaoImpl implements IUserDao{
    @Override
    public void addUser(User user) {
        System.out.println(user);
    }
}

在类上增加了一个注解Component,在类的开头使用了@Component注解,它可以被Spring容器识别,启动Spring后,会自动把它转成容器管理的Bean。

除了@Component外,Spring提供了3个功能基本和@Component等效的注解,分别对应于用于对DAO,Service,和Controller进行注解。
1:@Repository 用于对DAO实现类进行注解。
2:@Service 用于对业务层注解,但是目前该功能与 @Component 相同。
3:@Constroller用于对控制层注解,但是目前该功能与 @Component 相同。

修改以上的UserServiceImpl类,添加@Compotent注解:

package cn.liuw.service.impl;

import cn.liuw.dao.IUserDao;
import cn.liuw.po.User;
import cn.liuw.service.IUserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

/**
 * @ClassName UserServiceImpl
 * @Description TODO
 **/
@Component("userService")
public class UserServiceImpl implements IUserService{

    IUserDao userDao;

    @Override
    public void saveUser(User user) {
        //容器
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        //从容器中获取id = userDao的bean
        userDao = (IUserDao) context.getBean("userDao");
        System.out.println("开始添加用户...");
        userDao.addUser(user);
        System.out.println("结束添加用户...");
    }
}

以上添加了@Component注解,同时将无参构造方法中的语句放到了saveUser()方法中。避免无限循环加载Spring配置文件。

修改applicationContext.xml配置文件:




    
    

运行结果:

开始添加用户...
User{id=1, username='张三', sex='男', birthday=null, address='石家庄裕华区'}
结束添加用户...

4.2 其他

  • 作用域用scope来指定:@Scope("prototype")
  • Lazy延迟初始化Bean:@Lazy
  • 默认名称:如果使用Compont注解时不指定名称,基于@Componet及其扩展(如@Servic和自定义等)标注和classpath-scan定义的Bean,注解有一个value属性,如果提供了,那么就此Bean的名字。如果不提供。就会使用Spring默认的命名机制,即简单类名且第一个字母小写

五、自动装配

 从上一个示例中可以看出有两个位置都使用了ApplicationContext初始化容器后获得需要的Bean,可以通过自动装配简化。

5.1 自动装配

修改UserDaoImpl类的注解为:@Repository更为准确。

@Repository("userDao")
public class UserDaoImpl implements IUserDao{
    @Override
    public void addUser(User user) {
        System.out.println(user);
    }
}

修改UserServiceImpl类的注解为:@Service更为准确,同时为userDao属性添加上注解@AutoWired。

@Service("userService")
public class UserServiceImpl implements IUserService{
    @Autowired
    IUserDao userDao;

    @Override
    public void saveUser(User user) {
        System.out.println("开始添加用户...");
        userDao.addUser(user);
        System.out.println("结束添加用户...");
    }
}

@Autowired注解的作用是:可以对成员变量、方法和构造函数进行注解,来完成自动装配的工作,通俗来说就是会根据类型从容器中自动查到到一个Bean给userDao字段。@Autowired是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier。另外可以使用其它注解,@Resource :等同于@Qualifier,@Inject:等同于@Autowired。

@Service用于注解业务层组件(我们通常定义的service层就用这个)

@Controller用于注解控制层组件(如struts中的action)

@Repository用于注解数据访问组件,即DAO组件

@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行注解。

装配注解主要有:@Autowired、@Qualifier、@Resource,它们的特点是:

1、@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入;

2、@Autowired默认是按照类型装配注入的,如果想按照名称来转配注入,则需要结合@Qualifier一起使用;

3、@Resource注解是又J2EE提供,而@Autowired是由spring提供,故减少系统对spring的依赖建议使用@Resource的方式;如果Maven项目是1.5的JRE则需换成更高版本的。

4、@Resource和@Autowired都可以书写注解在字段或者该字段的setter方法之上

5、@Autowired 可以对成员变量、方法以及构造函数进行注释,而 @Qualifier 的注解对象是成员变量、方法入参、构造函数入参。

6、@Qualifier("XXX") 中的 XX是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。

7、@Autowired 注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个,通过属性required可以设置非必要。

8、@Resource装配顺序
  8.1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
  8.2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
  8.3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
  8.4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

5.2 多种注入方式

package cn.liuw.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class InjectTest {
    //注入给构造方法
    @Autowired
    public InjectTest(IUserDao dao2) {
        this.dao2=dao2;
    }

    //注入给成员变量,字段
    @Resource
    IUserDao dao1;
    IUserDao dao2;
    IUserDao dao3;
    IUserDao dao4;

    //注入给属性
    @Autowired
    public void setDao3(IUserDao dao3) {
        this.dao3 = dao3;
    }

    //注入给方法参数
    @Autowired
    public void injectDao4(IUserDao dao4, IUserDao dao5) {
        this.dao4 = dao4;
        System.out.println(dao5);
    }

    public static void main(String[] args) {
        ApplicationContext ctx =
                new ClassPathXmlApplicationContext("bookbean13.xml");
        InjectTest obj = ctx.getBean(InjectTest.class);
        System.out.println(obj.dao1);
        System.out.println(obj.dao2);
        System.out.println(obj.dao3);
        System.out.println(obj.dao4);
    }
}

interface IUserDao {
}

@Scope("prototype")
@Repository
class UserDao implements IUserDao {
}

运行结果:

cn.liuw.service.OrderDao@711a924b
cn.liuw.service.OrderDao@1442df6c
cn.liuw.service.OrderDao@325a35d8
cn.liuw.service.OrderDao@408511bb
cn.liuw.service.OrderDao@604f2d14

六、零配置实现IOC

6.1 零配置@Configuration案例

package cn.liuw.boot;

import cn.liuw.po.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @ClassName Applicationfg
 * @Description TODO
 **/
@Configuration
@ComponentScan(basePackages = "cn.liuw")
public class ApplicationCfg {

}

@Configuration相当于配置文件中的,ComponentScan相当于配置文件中的context:component-scan,属性也一样设置。
测试类:

import cn.liuw.boot.ApplicationCfg;
import cn.liuw.po.User;
import cn.liuw.service.IUserService;
import cn.liuw.service.impl.UserServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @ClassName Test03
 * @Description TODO
 **/
public class Test03 {
    @Test
    public void testSaveUser(){
        //获取容器
        ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationCfg.class);
        //从容器中获取UserServiceImpl对象
        IUserService userService = context.getBean(UserServiceImpl.class);
        //创建User对象
        User user = new User();
        user.setId(1);
        user.setUsername("张三");
        user.setSex("1");
        user.setAddress("河北邯郸");
        userService.saveUser(user);
    }
}

运行结果:

开始添加用户...
User{id=1, username='张三', sex='1', birthday=null, address='河北邯郸'}
结束添加用户...

 

零配置@Bean案例:

@Bean相当于,只能注解在方法和注解上,一般在方法上使用,方法名相当于id。

@Configuration
@ComponentScan(basePackages = "cn.liuw")
public class ApplicationCfg {
    @Bean
    public User getUser(){
        return new User();
    }
}

测试类:

@Test
public void testUser(){
	//容器
	ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationCfg.class);
	User user1 = context.getBean("getUser",User.class);
	System.out.println(user1);
}

运行结果:

User{id=0, username='null', sex='null', birthday=null, address='null'}

6.2 零配置由注解指定实例

package cn.liuw;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Repository;

public class NoXMLIoC {
    public static void main(String[] args) {
        //基于类型的配置
        ApplicationContext ctx=new AnnotationConfigApplicationContext(AppCfg.class);
        ICarDao dao1=ctx.getBean(ICarDao.class);
        dao1.add("Spring Pro");
    }
}

interface ICarDao{
    void add(String name);
}
@Repository
class CarDao implements ICarDao{
    public void add(String name) {
        System.out.println("添加"+name+"成功!");
    }
}
@Configuration
@ComponentScan(basePackages = "spring14")
class AppCfg{

}

6.3 零配置由方法指定实例

package cn.liuw;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Repository;

public class NoXMLIoC {
    public static void main(String[] args) {
        //基于类型的配置
        ApplicationContext ctx=new AnnotationConfigApplicationContext(AppCfg.class);
        ICarDao dao2=ctx.getBean("mysqlDao",ICarDao.class);
        dao2.add("Spring Pro");
    }
}

interface ICarDao{
    void add(String name);
}
class CarDao implements ICarDao{
    public void add(String name) {
        System.out.println("添加"+name+"成功!");
    }
}
@Configuration
@ComponentScan(basePackages = "spring14")
class AppCfg{
    @Bean
    ICarDao mysqlDao(){  //方法名就是bean的name
        return new CarDao();
    }
}

七、通过注解@Value获取properties配置

@value注解可以实现为对象赋值,可以直接指定值也可以从properties文件中获取,这里主要讲解两种方式:

7.1 使用XML实现

1. 在resource目录下创建一个properties文件,如db.properties:

jdbc.jdbcUrl=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=1234

2. 在Spring配置文件中导入资源文件




    
    
    

3. 通过@Value引用资源文件中的内容

package cn.liuw.util;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @ClassName DBUtil
 * @Description TODO
 **/
@Component
public class DBUtil {
    @Value("com.mysql.jdbc.Driver")
    private String driver;
    @Value("${jdbc.jdbcUrl}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "DBUtil{" +
                "driver='" + driver + '\'' +
                ", url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

4. 测试类

public class Test04 {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            DBUtil dbUtil = ctx.getBean(DBUtil.class);
            System.out.println(dbUtil);
        }
}

5. 运行结果

DBUtil{driver='com.mysql.jdbc.Driver', url='jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8', username='root', password='1234'}

7.2 使用零配置注解方式实现

1. 创建配置类

@Configuration
@ComponentScan("cn.liuw")
@PropertySource("db.properties")
public class SpringCfg {

}

2. 测试类

public class Test04 {
        public static void main(String[] args) {
            ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringCfg.class);
            IUserDao userDao = ctx.getBean(UserDaoImpl.class);
            //创建User对象
            User user = new User();
            user.setId(1);
            user.setUsername("李四");
            user.setAddress("北京市");
            //添加user
            userDao.addUser(user);
        }
}

3.运行结果

User{id=1, username='李四', sex='null', birthday=null, address='北京市'}

本文参考自:https://www.cnblogs.com/best/p/5727935.html

你可能感兴趣的:(Spring,FrameWork)