spring 笔记简单概述

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/uotail/article/details/81835973

spring系列教程

https://spring.io/docs/reference

Spring框架文档版本5.1.0.RC2

https://docs.spring.io/spring/docs/5.1.0.RC2/spring-framework-reference/

这部分参考文档涵盖了Spring Framework绝对不可或缺的所有技术。 

主要涉及到 IOC 和  DI及bean  的注入和 一些注解 ,介绍的很详细 ,我后面的文章主要是参考这个,

ps 回过头来看发现自己写的很垃圾。大家最好参考 官方文档

https://docs.spring.io/spring/docs/5.1.0.RC2/spring-framework-reference/core.html#spring-core

Spring Web MVC  讲的也很好  主要是映射那块和注解

https://docs.spring.io/spring/docs/5.1.0.RC2/spring-framework-reference/web.html#spring-web

Spring Framework事务管理  也很好讲到了 与jdbc hibernate 的集成

https://docs.spring.io/spring/docs/5.1.0.RC2/spring-framework-reference/data-access.html#spring-data-tier

这是4.3.18 的教程 ,是spring系列的集成

https://docs.spring.io/spring/docs/4.3.18.RELEASE/spring-framework-reference/htmlsingle/

1  什么是spring

    Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架
分层: 一站式,每一个层都提供的解决方案
web层:struts,spring-MVC
service层:spring
dao层:hibernate,mybatis , jdbcTemplate  --> spring-data
 

2 spring由来 

Spring是java平台上的一个开源应用框架。它的第一个版本是由Rod Johnson写出来的

Rod在他的Expert One-On-One Java EE Design and Development(Java企业应用设计与开发的专家一对一)一书中

首次发布了这个框架。

该框架也可以移植到.NET的环境下。

Spring的框架首次在2003年6月的Apache 2.0的使用许可中发布。

3 spring核心

Spring的核心是控制反转(IoC面向切面(AOP

Spring 最认同的技术是控制反转的依赖注入(DI模式。

控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。

Spring 框架的一个关键组件是面向方面的程序设计(AOP)框架。

有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。

4  spring优点

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

5 spring体系结构 

核心容器:beanscorecontextSpringExpression

核心容器:

核心容器提供 Spring 框架的基本功能。

核心容器的主要组件是 BeanFactory,它是工厂模式的实现。

BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开

 6 入门案例:IoC

1、创建源文件

2、创建 bean 的配置文件   只能配置可实例化的类,不能配置接口和抽象类

你需要创建一个 Bean 的配置文件,该文件是一个 XML 文件,并且作为粘合 bean 的粘合剂即类。这个文件需要在 src 目录下创建

Beans.xml 用于给不同的 bean 分配唯一的 ID,并且控制不同值的对象的创建,而不会影响 Spring 的任何源文件。

Spring 应用程序被加载到内存中时,框架利用了上面的配置文件来创建所有已经定义的 beans,并且按照 标签的定义为它们分配一个唯一的 ID。你可以使用 标签来传递在创建对象时使用不同变量的值。

3、运行程序

  • 第一步是我们使用框架 API ClassPathXmlApplicationContext() 来创建应用程序的上下文。

这个 API 加载 beans 的配置文件并最终基于所提供的 API,它处理创建并初始化所有的对象,即在配置文件中提到的 beans

  • 第二步是使用已创建的上下文的 getBean() 方法来获得所需的 bean。这个方法使用 bean ID 返回一个最终可以转换为实际对象的通用对象。一旦有了对象,你就可以使用这个对象调用任何类的方法。

 6.1  导入jar 包

      4 + 1  : 4个核心(beans、core、context、expression) + 1个依赖(commons-loggins...jar)

6.2 接口+目标类

  1. 提供UserService接口和实现类
  2. 获得UserService实现类的实例

       之前开发中,直接new一个对象即可。

       学习spring之后,将由Spring创建对象实例--> IoC 控制反转(Inverse of  Control

              之后需要实例对象时,从spring工厂(容器)中获得,需要将实现类的全限定名称配置到xml文件中

UserService接口

public interface UserService {

   public void addUser();

}

UserService实现类

public class UserServiceImpl implements UserService {

   @Override

   public void addUser() {

      System.out.println("a_ico add user");

   }

}

6.3 配置文件 

  1. 位置:任意,开发中一般在classpath下(src
  2. 名称:任意,beans.xml开发中常用applicationContext.xml
  3. 内容:添加schema约束

       约束文件位置:spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\ xsd-config.html

<?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">

    <!-- 配置service

        <bean> 配置需要创建的对象

            id :用于之后从spring容器获得实例时使用的

            class :需要创建实例的全限定类名

    -->

    <bean id="userServiceId" class="domain.UserServiceImpl"></bean>//包名.类名

</beans>

问题

The constructor ClassPathXmlApplicationContext(String) refers to the missing type

1 这是指该构造函数缺少了BeanException异常包。

    The constructor ClassPathXmlApplicationContext(String) refers to the missing type BeanException;

        所以我们添加了org.springframework.beans-3.0.4.RELEASE.jar注:其中context包依赖beans包。

 

 6.4 测试

@Test

    public void demo02(){

        //spring容器获得

        //1 获得容器

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“beans.xml”);

        //2获得内容 --不需要自己new,都是从spring容器获得

        UserService userService = (UserService) applicationContext.getBean("userServiceId");

        userService.addUser();

    }

7   spring IoC 容器

Spring 容器是 Spring 框架的核心

容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。

Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans

 

通过阅读配置元数据提供的指令,容器知道对哪些对象进行实例化,配置和组装。

配置元数据可以通过 XMLJava 注释或 Java 代码来表示。

下图是 Spring 如何工作的高级视图。

Spring IoC 容器利用 Java POJO 类和配置元数据来生成完全配置和可执行的系统或应用程序。

7.1 核心api

api整体了解,之后不使用,在学习过程需要

  1. BeanFactory :这是一个工厂,用于生成任意bean。

       采取延迟加载,第一次getBean时才会初始化Bean

  1. ApplicationContext:是BeanFactory的子接口,功能更强大。(国际化处理、事件传递、Bean自动装配、各种不同应用层的Context实现)。当配置文件被加载,就进行对象实例化。

ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactoryApplicationContext 会被推荐使用。

  1. WebXmlApplicationContext

 

       ClassPathXmlApplicationContext 用于加载classpath(类路径、src)下的xml

              加载xml运行时位置 --> /WEB-INF/classes/...xml

       FileSystemXmlApplicationContext 用于加载指定盘符下的xml

              加载xml运行时位置 --> /WEB-INF/...xml

                     通过java web ServletContext.getRealPath() 获得具体盘符

ApplicationContext context = new FileSystemXmlApplicationContext ("C:/Users/ZARA/workspace/HelloSpring/src/Beans.xml");

8 bean 

8.1 bean 定义

被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。

bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象

这些 bean 是由用容器提供的配置元数据创建的,bean 定义包含称为配置元数据的信息,

8.2 bean元素id和name属性的区别

在spring容器中添加以下配置:

<bean id="helloService" class="cn.hello.HelloService">

bean节点中Id和name的区别:

  1. 区别一
    1. id:指定唯一实例引用
    2. name:可以指定多个实例引用,例如name=“名称1,名称2”
  2. 区别二
    1. id :id的命名要满足XML对ID属性命名规范
      1. 例如:必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号
    2. name:如果Bean的名称中含有特殊字符,就需要使用name属性
      1. 例如:<bean name="# boy " class="cn.itcast.ioc.Boy"/>
      2. 因为name属性可以相同,所以后出现Bean会覆盖之前出现的同名的Bean

总结:项目开发的时候,强烈要求用id,因为id可以表示惟一引用。

8.3 bean作用域

当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。

Spring 框架支持以下五个作用域,

如果你使用 web-aware ApplicationContext 时,其中三个是可用的。

  1. 作用域:用于确定spring创建bean实例个数
  2. 取值:

       singleton 单例,默认值。

       prototype 多例,每执行一次getBean将获得一个实例。例如:struts整合spring,配置action多例。

  1. 配置信息

<bean id="" class=""  scope="">

      

 

<bean id="userServiceId" class="com.scope.UserServiceImpl"

      scope="prototype" ></bean>

8.3.1 singleton 作用域

如果作用域设置为 singleton,那么 Spring IoC 容器刚好创建一个由该 bean 定义的对象的实例。

该单一实例将存储在这种单例 bean 的高速缓存中,以及针对该 bean 的所有后续的请求和引用都返回缓存对象。

默认作用域是始终是 singleton

但是当仅仅需要 bean 的一个实例时,你可以在 bean 的配置文件中设置作用域的属性为 singleton,如下所示:

<!-- A bean definition with singleton scope -->

<bean id="..." class="..." scope="singleton">

    <!-- collaborators and configuration for this bean go here -->

</bean>

8.3.2 prototype 作用域

如果作用域设置为 prototype

那么每次特定的 bean 发出请求时 Spring IoC 容器就创建对象的新的 Bean 实例。

一般说来,满状态的 bean 使用 prototype 作用域和没有状态的 bean 使用 singleton 作用域。

Bean 生命周期

理解 Spring bean 的生命周期很容易。

当一个 bean 被实例化时,它可能需要执行一些初始化使它转换成可用状态。

同样,当 bean 不再需要,并且从容器中移除时,可能需要做一些清除工作。

为了定义安装和拆卸一个 bean,我们只要声明带有 init-method 和/或 destroy-method 参数。

init-method 属性指定一个方法,在实例化 bean 时,立即调用该方法。

同样,destroy-method 指定一个方法,只有从容器中移除 bean 之后,才能调用该方法。

9.1 初始化回调

第一种:org.springframework.beans.factory.InitializingBean 接口指定一个单一的方法:

void afterPropertiesSet() throws Exception;

因此,你可以简单地实现上述接口和初始化工作可以在 afterPropertiesSet() 方法中执行,如下所示:

public  class ExampleBean implements InitializingBean {  public void afterPropertiesSet() {
// do some initialization work }}

初始化在构造方法之后

第二种:在基于 XML 的配置元数据的情况下,你可以使用 init-method 属性来指定带有 void 无参数方法的名称。

例如:

<bean id= "exampleBean" class="examples.ExampleBean" init-method="init"/>

下面是类的定义:

public class ExampleBean {   public void init() {      // do some initialization work   }}

如果同时配置上面两种,顺序为构造---》接口---》xml配置

9.2  销毁回调

第一种 org.springframework.beans.factory.DisposableBean 接口指定一个单一的方法:

void destroy() throws Exception;

因此,你可以简单地实现上述接口并且结束工作可以在 destroy() 方法中执行,如下所示:

public class ExampleBean implements DisposableBean {
   public void destroy() {
      // do some destruction work
   }
}

第二种 在基于 XML 的配置元数据的情况下,你可以使用 destroy-method 属性来指定带有 void 无参数方法的名称。例如:

<bean id="exampleBean" class="examples.ExampleBean" destroy-method="destroy"/>

下面是类的定义

public class ExampleBean {
   public void destroy() {
      // do some destruction work
   }
}

如果你在非 web 应用程序环境中使用 Spring IoC 容器;

例如在丰富的客户端桌面环境中;那么 JVM 中你要注册关闭 hook。这样做可以确保正常关闭,为了让所有的资源都被释放,可以在单个 beans 上调用 destroy 方法。

建议你不要使用 InitializingBean 或者 DisposableBean 的回调方法,因为 XML 配置在命名方法上提供了极大的灵活性。

9.3 实例

这里是 HelloWorld.java 的文件的内容:
 

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}


下面是 MainApp.java 文件的内容。
在这里,你需要注册一个在 AbstractApplicationContext 类中声明的关闭 hook 的 registerShutdownHook() 方法。它将确保正常关闭,并且调用相关的 destroy 方法。

package com.tutorialspoint;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();
   }
}


下面是 init 和 destroy 方法必需的配置文件 Beans.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-3.0.xsd">
   <bean id="helloWorld" 
       class="com.tutorialspoint.HelloWorld"
       init-method="init" destroy-method="destroy">
       <property name="message" value="Hello World!"/>
   </bean>
</beans>


一旦你创建源代码和 bean 配置文件完成后,我们就可以运行该应用程序。如果你的应用程序一切都正常,将输出以下信息:
Bean is going through init.
Your Message : Hello World!
Bean will destroy now.

如果两种同时配置,接口优先级大于xml配置

9.4  默认的初始化和销毁方法

如果你有太多具有相同名称的初始化或者销毁方法的 Bean,那么你不需要在每一个bean中配置。

框架使用 元素中的 default-init-method  default-destroy-method 属性提供了灵活地配置这种情况,如下所示:

 

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"

    default-init-method="init"

default-destroy-method="destroy">

   <bean id="..." class="...">

       <!-- collaborators and configuration for this bean go here -->

   </bean>

</beans>

10 Bean 后置处理器

BeanPostProcessor 接口定义回调方法,你可以实现该方法来提供自己的实例化逻辑,依赖解析逻辑等。

你也可以在 Spring 容器通过插入一个或多个 BeanPostProcessor 的实现来完成实例化,配置和初始化一个bean之后实现一些自定义逻辑回调方法。

你可以配置多个 BeanPostProcesso r接口,通过设置 BeanPostProcessor 实现的 Ordered 接口提供的order 属性来控制这些 BeanPostProcessor 接口的执行顺序。

BeanPostProcessor 可以对 bean(或对象)实例进行操作,这意味着 Spring IoC 容器实例化一个 bean 实例,然后 BeanPostProcessor 接口进行它们的工作。

ApplicationContext 会自动检测由 BeanPostProcessor 接口的实现定义的 bean,注册这些 bean 为后置处理器然后通过在容器中创建 bean,在适当的时候调用它。

这里是 HelloWorld.java 文件的内容:

package com.tutorialspoint;
public class HelloWorld {
   private String message;
   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}

这是实现 BeanPostProcessor 的非常简单的例子,它在任何 bean 的初始化的之前和之后输入该 bean 的名称

你可以在初始化 bean 的之前和之后实现更复杂的逻辑,因为你有两个访问内置 bean 对象的后置处理程序的方法。

这里是 InitHelloWorld.java 文件的内容:

package com.tutorialspoint;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
public class InitHelloWorld implements BeanPostProcessor {
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("BeforeInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("AfterInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
}

下面是 MainApp.java 文件的内容。在这里,你需要注册一个在 AbstractApplicationContext 类中声明的关闭 hook 的 registerShutdownHook() 方法。它将确保正常关闭,并且调用相关的 destroy 方法。

package com.tutorialspoint;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();
   }
}

下面是 init 和 destroy 方法需要的配置文件 Beans.xml 文件:

将后处理的实现类注册给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-3.0.xsd">

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld"
       init-method="init" destroy-method="destroy">
       <property name="message" value="Hello World!"/>
   </bean>
   <bean class="com.tutorialspoint.InitHelloWorld" />

</beans>

一旦你创建源代码和 bean 配置文件完成后,我们就可以运行该应用程序。如果你的应用程序一切都正常,将输出以下信息:

BeforeInitialization : helloWorld

Bean is going through init.

AfterInitialization : helloWorld

Your Message : Hello World!

Bean will destroy now.

Bean后置处理器执行在bean的初始化最前后,即构造之后(紧挨),不是销毁之后

问题1:后处理bean作用某一个目标类,还是所有目标类?

       所有

问题2:如何只作用一个?

       通过“参数2”beanName进行控制

11 Bean 定义继承

bean 定义可以包含很多的配置信息,包括构造函数的参数,属性值,容器的具体信息例如初始化方法,静态工厂方法名,等等。

bean 的定义继承父定义的配置数据。子定义可以根据需要重写一些值,或者添加其他值。

Spring Bean 定义的继承与 Java 类的继承无关,但是继承的概念是一样的。你可以定义一个父 bean 的定义作为模板和其他子 bean 就可以从父 bean 中继承所需的配置。

当你使用基于 XML 的配置元数据时,通过使用父属性,指定父 bean 作为该属性的值来表明子 bean 的定义。

下面是配置文件 Beans.xml,在该配置文件中我们定义有两个属性 message1  message2  “helloWorld” bean。然后,使用 parent 属性 “helloIndia” bean 定义为 “helloWorld” bean 的孩子。这个子 bean 继承 message2 的属性,重写 message1 的属性,并且引入一个属性 message3

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

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
      <property name="message1" value="Hello World!"/>
      <property name="message2" value="Hello Second World!"/>
   </bean>

   <bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="helloWorld">
      <property name="message1" value="Hello India!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>

</beans>

Bean 定义模板

你可以创建一个 Bean 定义模板,不需要花太多功夫它就可以被其他子 bean 定义使用。

在定义一个 Bean 定义模板时,你不应该指定的属性,而应该指定带 true 值的抽象属性,如下所示:

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

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="beanTeamplate" abstract="true">
      <property name="message1" value="Hello World!"/>
      <property name="message2" value="Hello Second World!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>

   <bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="beanTeamplate">
      <property name="message1" value="Hello India!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>

</beans>

bean 自身不能被实例化,因为它是不完整的,而且它也被明确地标记为抽象的

当一个定义是抽象的,它仅仅作为一个纯粹的模板 bean 定义来使用的,充当子定义的父定义使用。

 

12 装配Bean和属性依赖注入

12.1 使用构造方法实例化

  1. 在spring容器中配置

<?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">

   <!--2  第一种方式 默认构造 -->

   <bean id="demo1User" class="cn.demo1.User"></bean>

</beans>

  1. 测试

public static void main(String[] args) {

     

      ApplicationContext applicationContext =

new ClassPathXmlApplicationContext("applicationContext.xml");

      User user = (User)applicationContext.getBean("demo1User");

      System.out.println(user);

}

  1. 对比

相当于:User user = new User(); //直接创建实例

先简单说下后面详解

12.2 使用静态工程方法实例化

不用指定factorybean直接用class指定静态工厂类

定义使用静态工厂方法创建的bean时,您可以使用该class 属性来指定包含static工厂方法的类和一个factory-method指定工厂方法名称的属性。

  1. 在spring容器中配置

<?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">

 

   <!-- 第二种方式 静态工厂方法 没有工厂的实例对象-->

   <bean id="demo2User" class="cn.demo2.Demo2BeanFactory" factory-method="getDemo2Bean"></bean>

  

</beans>

  1. 提供工厂类

package cn.demo2;

public class Demo2BeanFactory {

   public Demo2BeanFactory(){

      System.out.println("demo2 不执行");

   }

   /**

    * 必须提供 static方法

    * @return

    */

   public static User getDemo2Bean(){

      return new User();

   }

}

  1. 测试

public static void main(String[] args) {

      ApplicationContext applicationContext =

new ClassPathXmlApplicationContext("applicationContext.xml");

      User user = (User)applicationContext.getBean("demo2User");

      System.out.println(user);

   }

  1. 对比

相当于: User user = BeanFatory.getUserBean();      //通过工厂的静态方法获得需要的内容

12.3 使用实例工程方法

与通过静态工厂方法的实例化类似,使用实例工厂方法实例化从容器调用现有bean的非静态方法来创建新bean。要使用此机制,请将该class属性保留为空,并在factory-bean属性中指定包含要调用以创建对象的实例方法的当前(或父/祖先)容器中的bean的名称。

使用factory-method属性设置工厂方法本身的名称。

一个工厂类也可以持有多种工厂方法,如下所示:

<bean  id = “serviceLocator”  class = “examples.DefaultServiceLocator” > 
    <! - 注入此定位器bean所需的任何依赖关系 - > 
</ bean>

“bean  id = ”clientService“ 
    factory-bean = ”serviceLocator“ 
    factory-method = ”createClientServiceInstance“ />

<bean  id = “accountService” 
    factory-bean = “serviceLocator” 
    factory-method = “createAccountServiceInstance” />
public  class DefaultServiceLocator {

    private  static ClientService clientService = new ClientServiceImpl();
    private  static AccountService accountService = new AccountServiceImpl();

    private DefaultServiceLocator(){}

    public ClientService createClientServiceInstance(){
         return clientService;
    }

    public AccountService createAccountServiceInstance(){
         return accountService;
    }

}

这种方法表明工厂bean本身可以通过依赖注入(DI)进行管理和配置。

Spring文档中,工厂bean是指在Spring容器中配置的bean,它将通过实例 静态工厂方法创建对象 。相比之下, FactoryBean(注意大写)是指Spring特定的 FactoryBean

第二个例子

  1. 在Spring容器的配置

<?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">

   <!-- 第三种方式 实例工厂方法

      * 先实例工厂

      * 通过实例工厂执行具体的方法

    -->

   <bean id="demo3BeanFactory" class="cn.demo3.Demo3BeanFactory"></bean>

   <bean id="demo3User" factory-bean="demo3BeanFactory" factory-method="getDemo2Bean"></bean>

</beans>

  1. 提供工厂类

package cn.demo3;

public class Demo3BeanFactory {

  

   public Demo3BeanFactory(){

      //System.out.println("demo3 执行");

   }

 

   /**

    * 非静态方法

    * @return

    */

   public User getDemo2Bean(){

      return new User();

   }

 

}

 

  1. 测试

   public static void main(String[] args) {

     

      ApplicationContext applicationContext =

new ClassPathXmlApplicationContext("applicationContext.xml");

      User user = (User)applicationContext.getBean("demo3User");

      System.out.println(user);

   }

  1. 对比

相当于:

BeanFactory factory = new BeanFactory();          //先创建工厂

User user = factory.getUserBean();                     //在通过工厂的实例对象,执行非静态方法获得具体内容

12.3  Bean种类

普通bean:之前操作的都是普通bean。<bean id="" class="A"> ,spring直接创建A实例,并返回

bean工厂:不是bean,在spring中一般指的是DefaultListableBeanFactory对象,管理和维护spring中所有的bean

工厂bean(自己可以创建)一种特殊的bean,在xml文件中配置的,用来生成新的bean的加工厂,通过getObject()方法可以获取其生产的新bean,如果想获取该工厂bean本身,需要使用类似于getBean("&" + beanName)的样式。

12.4 依赖注入

依赖注入DI)是一个过程,

容器在创建bean注入这些依赖项。这个过程基本上是反向的,

通过DI原理,代码更清晰,当对象具有依赖关系时,解耦更有效。对象不查找其依赖关系,并且不知道依赖关系的位置或类。因此,您的类变得更容易测试,特别是当依赖关系在接口或抽象基类上时,允许在单元测试中使用存根或模拟实现。

DI存在两种主要的变体:基于构造函数的依赖注入基于Setter的依赖注入

12.4.1 基于构造函数的依赖注入

私有化属性并在构造中初始化属性

public class SimpleMovieLister {
    // the SimpleMovieLister has a dependency on a MovieFinder
    private MovieFinder movieFinder;
    // a constructor so that the Spring container can inject a MovieFinder
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // business logic that actually uses the injected MovieFinder is omitted...
}

 构造函数参数解析:

 使用参数的类型进行构造函数参数解析匹配。如果在bean定义的构造函数参数中不存在潜在的歧义,那么在bean定义中定义构造函数参数的顺序就是当bean被实例化时这些参数被提供给适当构造函数的顺序。

package x.y;
public class Foo {
    public Foo(Bar bar, Baz baz) {
        // ...
    }
}

没有潜在的歧义存在,假设BarBaz类与继承无关。因此,以下配置工作正常,您不需要在<constructor-arg/> 元素中明确指定构造函数参数索引和/或类型。

bean> 
    <bean  id = “foo”  class = “xyFoo” > 
        <constructor-arg  ref = “bar” /> 
        <constructor-arg  ref = “baz” /> 
    </ bean>
    <bean  id = “bar”  class = “xyBar” />
    <bean  id = “baz”  class = “xyBaz” /> 
</ beans>

当引用另一个bean时,该类型是已知的,并且可以进行匹配(如前面的示例所示)。

当使用简单类型时,例如 <value>true</value>Spring无法确定值的类型,因此无法通过类型匹配,无需帮助。考虑下面的类:

package examples;

public class ExampleBean {
    // Number of years to calculate the Ultimate Answer
    private int years;
    // The Answer to Life, the Universe, and Everything
    private String ultimateAnswer;
    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }
}

在上述情况下,如果使用该属性显式指定构造函数参数的类型,则容器可以使用与简单类型匹配的类型type

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>

使用该index属性来明确指定构造函数参数的索引

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>

除了解决多个简单值的歧义之外,指定索引会解析构造函数具有两个相同类型参数的歧义。请注意, 索引为0

您还可以使用构造函数参数名称进行值消除歧义:

<bean  id = “exampleBean”  class = “examples.ExampleBean” > 
    <constructor-arg  name = “years”  value = “7500000” /> 
    <constructor-arg  name = “ultimateAnswer”  value = “42” /> 
</ bean >

请记住,为了使这项工作成功,您的代码必须在启用调试标志的情况下进行编译,以便Spring可以从构造函数中查找参数名称。如果您无法使用调试标志(或不想)编译代码,则可以使用 @ConstructorProperties JDK注释来明确命名构造函数参数。然后样本类必须如下所示:

package examples;

public class ExampleBean {
    // Fields omitted
    @ConstructorProperties({"years", "ultimateAnswer"})
    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }
}

最后,如果你想要向一个对象传递一个引用,你需要使用 标签的 ref 属性,

如果你想要直接传递值,那么你应该使用如上所示的 value 属性。

12.4.2 基于设值函数的依赖注入

私有属性,需要提供注入属性的set方法,、get方法不是必须(尽量有)

当容器调用一个无参的构造函数或一个无参的静态 factory 方法来初始化你的 bean 后,

通过容器在你的 bean 上调用设值函数,基于设值函数的 DI 就完成了。

基于Setter DI通过在调用无参数构造函数或无参数static工厂方法来实例化bean之后,通过容器调用beansetter方法来实现。

以下示例显示一个只能使用纯setter注入进行依赖注入的类。这个类是常规Java。它是一个POJO,它不依赖容器特定的接口,基类或注释。

public class SimpleMovieLister {
    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;
    // a setter method so that the Spring container can inject a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // business logic that actually uses the injected MovieFinder is omitted...
}

在这里,你需要检查设值函数方法的名称转换

要设置一个变量 spellChecker,我们使用setSpellChecker() 方法,该方法与 Java POJO 类非常相似

<!-- setter方法注入

        * 普通数据

            <property name="" value=""> name需要与属性名一致

            等效

            <property name="">

                <value>

        * 引用数据

            <property name="" ref="另一个bean">

            等效

            <property name="">

                <ref bean="另一个bean"/>

12.4.3 区别

你应该注意定义在基于构造函数注入和基于设值函数注入中的 Beans.xml 文件的区别。

唯一的区别就是在基于构造函数注入中,我们使用的是 标签constructor-arg中的 元素,

而在基于设值函数的注入中,我们使用的是 标签property中的 元素。

第二个你需要注意的点是,如果你要把一个引用传递给一个对象,那么你需要使用 标签的 ref 属性,而如果你要直接传递一个值,那么你应该使用 value 属性。

12.5  注入内部bean

注入内部 Beans

正如你所知道的 Java 内部类是在其他类的范围内被定义的,

同理,inner beans 是在其他 bean 的范围内定义的 bean。因此在 元素内 元素被称为内部bean,如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="outerBean" class="...">
      <property name="target">
         <bean id="innerBean" class="..."/>
      </property>
   </bean>
</beans>

这里是 TextEditor.java 文件的内容:

package com.tutorialspoint;
public class TextEditor {
   private SpellChecker spellChecker;
   // a setter method to inject the dependency.
   public void setSpellChecker(SpellChecker spellChecker) {
      System.out.println("Inside setSpellChecker." );
      this.spellChecker = spellChecker;
   }  
   // a getter method to return spellChecker
   public SpellChecker getSpellChecker() {
      return spellChecker;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}

下面是另一个依赖的类文件 SpellChecker.java 内容:

package com.tutorialspoint;
public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling(){
      System.out.println("Inside checkSpelling." );
   }   
}

下面是 MainApp.java 文件的内容:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      TextEditor te = (TextEditor) context.getBean("textEditor");
      te.spellCheck();
   }
}

下面是使用内部 bean 为基于 setter 注入进行配置的配置文件 Beans.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-3.0.xsd">

   <!-- Definition for textEditor bean using inner bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <property name="spellChecker">
         <bean id="spellChecker" class="com.tutorialspoint.SpellChecker"/>
       </property>
   </bean>
</beans>

一旦你创建源代码和 bean 配置文件完成后,我们就可以运行该应用程序。如果你的应用程序一切都正常,将输出以下信息:

 

12.6 注入集合

12.6.1

<!--

        集合的注入都是给<property>添加子标签

            数组:<array>

            List<list>

            Set<set>

            Map<map> map存放k/v 键值对,使用<entry>描述

            Properties<props>  <prop key=""></prop>  【】

        普通数据:<value>

        引用数据:<ref>

    -->

    <bean id="collDataId" class="" >

        <property name="arrayData">

            <array>

                <value>DS</value>

                <value>DZD</value>

                <value>屌丝</value>

                <value>屌中屌</value>

            </array>

        </property>

       

        <property name="listData">

            <list>

                <value>于嵩楠</value>

                <value>曾卫</value>

                <value>杨煜</value>

                <value>曾小贤</value>

            </list>

        </property>

       

        <property name="setData">

            <set>

                <value>停封</value>

                <value>薄纸</value>

                <value>关系</value>

            </set>

        </property>

       

        <property name="mapData">

            <map>

                <entry key="jack" value="杰克"></entry>

                <entry>

                    <key><value>rose</value></key>

                    <value>肉丝</value>

                </entry>

            </map>

        </property>

       

        <property name="propsData">

            <props>

                <prop key="高富帅"></prop>

                <prop key="白富美"></prop>

                <prop key="男屌丝"></prop>

            </props>

        </property>

    </bean>

12.6.2注入 Bean 引用作为集合元素

下面的 Bean 定义将帮助你理解如何注入 bean 的引用作为集合的元素。甚至你可以将引用和值混合在一起,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <!-- Bean Definition to handle references and values -->
   <bean id="..." class="...">
      <!-- Passing bean reference  for java.util.List -->
      <property name="addressList">
         <list>
            <ref bean="address1"/>
            <ref bean="address2"/>
            <value>Pakistan</value>
         </list>
      </property>
      <!-- Passing bean reference  for java.util.Set -->
      <property name="addressSet">
         <set>
            <ref bean="address1"/>
            <ref bean="address2"/>
            <value>Pakistan</value>
         </set>
      </property>
      <!--Passing bean reference  for java.util.Map -->
      <property name="addressMap">
         <map>
            <entry key="one" value="INDIA"/>
            <entry key ="two" value-ref="address1"/>
            <entry key ="three" value-ref="address2"/>
         </map>
      </property>
   </bean>
</beans>

 为了使用上面的 bean 定义,你需要定义 setter 方法,它们应该也能够是用这种方式来处理引用。

12.7   注入 null 和空字符串的值

如果你需要传递一个空字符串作为值,那么你可以传递它,如下所示:

<bean id="..." class="exampleBean">
   <property name="email" value=""/>
</bean>

前面的例子相当于 Java 代码:exampleBean.setEmail("")

 

如果你需要传递一个 NULL 值,那么你可以传递它,如下所示:

<bean id="..." class="exampleBean">
   <property name="email"><null/></property>
</bean>

前面的例子相当于 Java 代码:exampleBean.setEmail(null)

12.9 使用依赖

如果一个bean是另一个bean的依赖,通常意味着一个bean被设置为另一个的属性。通常,您可以使用基于XML的配置元数据中的<ref/> 元素来实现此目的。

但是,有时bean之间的依赖关系较少例如,需要触发类中的静态初始化器,例如数据库驱动程序注册

depends-on使用此元素的bean初始化之前,该属性可以显式强制一个或多个bean进行初始化。

以下示例使用该depends-on属性来表示对单个bean的依赖关系:

<bean  id = “beanOne”  class = “ExampleBean”  depends-on = “manager” /> 
<bean  id = “manager”  class = “ManagerBean” />

要表示对多个bean的依赖,请提供一个bean名称列表作为depends-on属性的值,并使用逗号,空格和分号作为有效的分隔符:

<bean  id = “beanOne”  class = “ExampleBean”  depends-on = “manager,accountDao” > 
  <property  name = “manager”  ref = “manager” /> 
</ bean>
<bean  id = “manager”  class = “ManagerBean” /> 
<bean  id = “accountDao”  class = “xyjdbc.JdbcAccountDao” />

12.10 Lazy初始化的bean

默认情况下,ApplicationContext实现在初始化过程的一部分中热切地创建和配置所有 单例 bean。通常,这种预实例化是可取的,因为配置或周围环境中的错误被立即发现,而不是几个小时甚至几天。当发生这种情况是理想的,你可以通过标记bean定义为延迟初始化,防止单豆的预实例化。一个lazy初始化的bean告诉IoC容器在首次请求时创建一个bean实例,而不是在启动时。

XML中,此行为由 元素lazy-init上的属性控制<bean/>例如:

“bean  id = ”lazy“  class = ”com.foo.ExpensiveToCreateBean“  lazy-init = ”true“ /> 
<bean  name = ”not.lazy“  class = ”com.foo.AnotherBean“ />

当前面的配置被一个消耗时ApplicationContext,命名的bean lazyApplicationContext启动时不会被预先实例化,而not.lazybean是热切地预先实例化的。

但是,当一个惰性初始化的bean是一个不被惰性初始化的单例bean的依赖项时 ,它ApplicationContext会在启动时创建懒惰初始化的bean,因为它必须满足单例的依赖性

lazy初始化的bean被注入到其他不是懒惰初始化的单例bean中。

您还可以通过使用元素default-lazy-init上的属性来控制容器级别的延迟初始化 <beans/>例如:

<beans  default-lazy-init = “true” > <! - 没有bean将被实例化...  - > </ beans>

13 bean自动装配

下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。

你可以使用<bean>元素的autowire 属性为一个 bean 定义指定自动装配模式。

模式

描述

no

这是默认的设置,它意味着没有自动装配,你应该使用显式的bean引用来连线。你不用为了连线做特殊的事。在依赖注入章节你已经看到这个了。

byName

由属性名自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byName。然后尝试匹配,并且将它的属性与在配置文件中被定义为相同名称的 beans 的属性进行连接。

byType

由属性数据类型自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byType。然后如果它的类型匹配配置文件中的一个确切的 bean 名称,它将尝试匹配和连接属性的类型。如果存在不止一个这样的 bean,则一个致命的异常将会被抛出。

constructor

类似于 byType,但该类型适用于构造函数参数类型。如果在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。

autodetect

Spring首先尝试通过 constructor 使用自动装配来连接,如果它不执行,Spring 尝试通过 byType 来自动装配。

可以使用 byType 或者 constructor 自动装配模式来连接数组和其他类型的集合。

  1. 自动装配的局限性

当自动装配始终在同一个项目中使用时,它的效果最好。如果通常不使用自动装配,它可能会使开发人员混淆的使用它来连接只有一个或两个 bean 定义。

不过,自动装配可以显著减少需要指定的属性或构造器参数,但你应该在使用它们之前考虑到自动装配的局限性和缺点。

限制

描述

重写的可能性

你可以使用总是重写自动装配的 <constructor-arg> <property> 设置来指定依赖关系。

原始数据类型

你不能自动装配所谓的简单类型包括基本类型,字符串和类。

混乱的本质

自动装配不如显式装配精确,所以如果可能的话尽可能使用显式装配。

 

  1. 自动装配 ‘byName’

这种模式由属性名称指定自动装配

Spring 容器看作 beans,在 XML 配置文件中 beans  auto-wire 属性设置为 byName

然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。

如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。

例如,在配置文件中,如果一个 bean 定义设置为自动装配 byName,并且它包含 spellChecker 属性(即,它有一个 setSpellChecker(...) 方法),那么 Spring 就会查找定义名为 spellChecker  bean,并且用它来设置这个属性。

你仍然可以使用 <property> 标签连接其余的属性。下面的例子将说明这个概念。

这里是 TextEditor.java 文件的内容:

package com.tutorialspoint;
public class TextEditor {
   private SpellChecker spellChecker;
   private String name;
   public void setSpellChecker( SpellChecker spellChecker ){
      this.spellChecker = spellChecker;
   }
   public SpellChecker getSpellChecker() {
      return spellChecker;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getName() {
      return name;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}

下面是另一个依赖类文件 SpellChecker.java 的内容:

package com.tutorialspoint;
public class SpellChecker {
   public SpellChecker() {
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   }   
}

下面是 MainApp.java 文件的内容:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = 
             new ClassPathXmlApplicationContext("Beans.xml");
      TextEditor te = (TextEditor) context.getBean("textEditor");
      te.spellCheck();
   }
}

下面是在正常情况下的配置文件 Beans.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-3.0.xsd">
   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
       <property name="spellChecker" ref="spellChecker" />
       <property name="name" value="Generic Text Editor" />
   </bean>
   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>
</beans>

但是,如果你要使用自动装配 “byName”,那么你的 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-3.0.xsd">
   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor" autowire="byName">
      <property name="name" value="Generic Text Editor" />
   </bean>
   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>
</beans>

一旦你完成了创建源代码和 bean 的配置文件,我们就可以运行该应用程序。如果你的应用程序一切都正常,它将打印下面的消息:

Inside SpellChecker constructor.
Inside checkSpelling.

https://www.w3cschool.cn/wkspring/fwdz1mmb.html

14 注解配置

 

Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。

XML 注入之前进行注解注入,因此后者的配置将通过两种方式的属性连线被前者重写。

注解连线在默认情况下在 Spring 容器中不打开。因此,在可以使用基于注解的连线之前,我们将需要在我们的 Spring 配置文件中启用它

所以如果你想在 Spring 应用程序中使用的任何注解,可以考虑到下面的配置文件。

添加3context约束并打开注解

一般我们只需配置包扫描

<context:component-scan base-package="domain"></c ontext:component-scan>
<?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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   <context:annotation-config/>
   <!-- bean definitions go here -->
</beans>

一旦 被配置后,你就可以开始注解你的代码,表明 Spring 应该自动连接值到属性,方法和构造函数。让我们来看看几个重要的注解,并且了解它们是如何工作的:

序号

注解 & 描述

1

@Required

@Required 注解应用于 bean 属性的 setter 方法。

2

@Autowired

@Autowired 注解可以应用到 bean 属性的 setter 方法,非 setter 方法,构造函数和属性。

3

@Qualifier

通过指定确切的将被连线的 bean@Autowired @Qualifier 注解可以用来删除混乱。

4

JSR-250 Annotations

Spring 支持 JSR-250 的基础的注解,其中包括了 @Resource@PostConstruct @PreDestroy 注解。

14.1 @Required 注释

Spring @Required 注释

请注意, setter方法使用@Required注释可以用于使属性成为必需的依赖关系。

@Required 注释应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中,否则容器就会抛出一个 BeanInitializationException 异常。

下面显示的是一个使用 @Required 注释的示例。

下面是 Student.java 文件的内容:

package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Required;
public class Student {
   private Integer age;
   private String name;
   @Required
   public void setAge(Integer age) {
      this.age = age;
   }
   public Integer getAge() {
      return age;
   }
   @Required
   public void setName(String name) {
      this.name = name;
   }
   public String getName() {
      return name;
   }
}

下面是 MainApp.java 文件的内容:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      Student student = (Student) context.getBean("student");
      System.out.println("Name : " + student.getName() );
      System.out.println("Age : " + student.getAge() );
   }
}

下面是配置文件 Beans.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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   <context:annotation-config/>
   <!-- Definition for student bean -->
   <bean id="student" class="com.tutorialspoint.Student">
      <property name="name"  value="Zara" />
      <!-- try without passing age and check the result -->
      <!-- property name="age"  value="11"-->
   </bean>
</beans>

一旦你已经完成的创建了源文件和 bean 配置文件,让我们运行一下应用程序。

如果你的应用程序一切都正常的话,这将引起 BeanInitializationException 异常,并且会输出一下错误信息和其他日志消息:

Property 'age' is required for bean 'student'

 

下一步,在你按照如下所示从 “age” 属性中删除了注释,你可以尝试运行上面的示例:

现在上面的示例将产生如下结果:

Name : Zara
Age : 11
 

14.2 @Autowired 注释

@Autowired 注释对在哪里和如何完成自动连接提供了更多的细微的控制。

@Autowired 注释可以在 setter 方法中被用于自动连接 bean,就像 @Autowired 注释,容器,一个属性或者任意命名的可能带有多个参数的方法。

@Autowired顾名思义,就是自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。当然,getter看个人需求,如果私有属性需要对外提供的话,应当予以保留。

 

14.2.1 Setter 方法中的 @Autowired

你可以在 XML 文件中的 setter 方法中使用 @Autowired 注释来除去 元素

当 Spring遇到一个在 setter 方法中使用的 @Autowired 注释,它会在方法中试图执行 byType 自动连接

这里是 TextEditor.java 文件的内容:

package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
   private SpellChecker spellChecker;
   @Autowired
   public void setSpellChecker( SpellChecker spellChecker ){
      this.spellChecker = spellChecker;
   }
   public SpellChecker getSpellChecker( ) {
      return spellChecker;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}

下面是另一个依赖的类文件 SpellChecker.java 的内容:

package com.tutorialspoint;
public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling(){
      System.out.println("Inside checkSpelling." );
   }  
}

下面是 MainApp.java 文件的内容:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      TextEditor te = (TextEditor) context.getBean("textEditor");
      te.spellCheck();
   }
}

下面是配置文件 Beans.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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   <context:annotation-config/>
   <!-- Definition for textEditor bean without constructor-arg  -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor"> </bean>
   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker"> </bean>
</beans>

一旦你已经完成的创建了源文件和 bean 配置文件,让我们运行一下应用程序。如果你的应用程序一切都正常的话,这将会输出以下消息:

 

 

14.2.2 属性中的 @Autowired

你可以在属性中使用 @Autowired 注释来除去 setter 方法(get方法不是必须)

当时使用 为自动连接属性传递的时候,Spring 会将这些传递过来的值或者引用自动分配给那些属性。

所以利用在属性中 @Autowired 的用法,你的TextEditor.java 文件将变成如下所示:

package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
   @Autowired
   private SpellChecker spellChecker;
   public TextEditor() {
      System.out.println("Inside TextEditor constructor." );
   }  
   public SpellChecker getSpellChecker( ){
      return spellChecker;
   }  
   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}

下面是配置文件 Beans.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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   <context:annotation-config/>
   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor"> </bean>
   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker"></bean>
</beans>

一旦你在源文件和 bean 配置文件中完成了上面两处改变,让我们运行一下应用程序。如果你的应用程序一切都正常的话,这将会输出以下消息:

14.2.3  构造函数中的 @Autowired

你也可以在构造函数中使用 @Autowired

You can apply the @Autowired annotation to constructors:

一个构造函数 @Autowired 说明当创建 bean 时,即使在 XML 文件中没有使用 元素配置 bean ,构造函数也会被自动连接。

即不用再写set和get方法

让我们检查一下下面的示例。

这里是 TextEditor.java 文件的内容:

package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
   private SpellChecker spellChecker;
   @Autowired
   public TextEditor(SpellChecker spellChecker){
      System.out.println("Inside TextEditor constructor." );
      this.spellChecker = spellChecker;
   }
   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}

下面是配置文件 Beans.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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   <context:annotation-config/>
   <!-- Definition for textEditor bean without constructor-arg  -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor"></bean>
   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker"></bean>
</beans>

一旦你在源文件和 bean 配置文件中完成了上面两处改变,让我们运行一下应用程序。如果你的应用程序一切都正常的话,这将会输出以下消息:

14.2.4 @Autowired 的(required=false)选项

默认情况下,@Autowired 注释意味着依赖是必须的

Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

然而,你可以使用 @Autowired  required=false 选项关闭默认行为。

每个类只有一个注释构造函数可以被标记为必需,但是可以注释多个非必需的构造函数。

在这种情况下,每个候选者都被考虑,Spring使用最可靠的构造函数,它的依赖关系可以被满足,也就是具有最大参数数量的构造函数。

14.3  @Qualifier 注释不常用

http://www.cnblogs.com/smileLuckBoy/p/5801678.html

可能会有这样一种情况,当你创建多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,

在这种情况下,你可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。下面显示的是使用 @Qualifier 注释的一个示例。

这里是 Student.java 文件的内容:

package com.tutorialspoint;
public class Student {
   private Integer age;
   private String name;
   public void setAge(Integer age) {
      this.age = age;
   }   
   public Integer getAge() {
      return age;
   }
   public void setName(String name) {
      this.name = name;
   }  
   public String getName() {
      return name;
   }
}

这里是 Profile.java 文件的内容:

package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Profile {
   @Autowired
   @Qualifier("student1")
   private Student student;
   public Profile(){
      System.out.println("Inside Profile constructor." );
   }
   public void printAge() {
      System.out.println("Age : " + student.getAge() );
   }
   public void printName() {
      System.out.println("Name : " + student.getName() );
   }
}

下面是 MainApp.java 文件的内容:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      Profile profile = (Profile) context.getBean("profile");
      profile.printAge();
      profile.printName();
   }
}

考虑下面配置文件 Beans.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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   <context:annotation-config/>
   <!-- Definition for profile bean -->
   <bean id="profile" class="com.tutorialspoint.Profile"></bean>
   <!-- Definition for student1 bean -->
   <bean id="student1" class="com.tutorialspoint.Student">
      <property name="name"  value="Zara" />
      <property name="age"  value="11"/>
   </bean>
   <!-- Definition for student2 bean -->
   <bean id="student2" class="com.tutorialspoint.Student">
      <property name="name"  value="Nuha" />
      <property name="age"  value="2"/>
   </bean>
</beans>

一旦你在源文件和 bean 配置文件中完成了上面两处改变,让我们运行一下应用程序。如果你的应用程序一切都正常的话,这将会输出以下消息:

Inside Profile constructor.Age : 11
Name : Zara

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/uotail/article/details/81835973