spring(二)

发布于:2022-11-09 ⋅ 阅读:(550) ⋅ 点赞:(0)

一、依赖注入DI

1、概念

依赖:指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .

注入:指Bean对象所依赖的资源 , 由容器来设置和装配

依赖注入就是当一个bean实例引用到了另外一个bean实例时spring容器帮助我们创建依赖bean实例并注入(传递)到另一个bean中,如上述案例中的AccountService依赖于AccountDao,Spring容器会在创建AccountService的实现类和AccountDao的实现类后,把AccountDao的实现类注入AccountService实例中,下面分别介绍setter注入和构造函数注入。

2、注入方式

(1)、构造器注入

构造器注入即被注入的属性需要有set方法, Setter注入支持简单类型和引用类型,Setter注入时在bean实例创建完成后执行的。

构造器注入依赖于构造方法实现,采用反射的方式,通过使用构造方法来完成注入,构造器注入在元素里声明属性

四种常见的构造器注入的方式:无参构造、索引匹配、类型匹配、名称匹配

定义一个JavaBean对象,为其提供构造方法

spring配置文件context.xml

测试

在配置文件中配置该类的bean,并配置构造器,在配置构造器中用到了<constructor-arg>节点,该节点有四个属性:

  • index是索引,指定注入的属性,从0开始,如:0代表personDao,1代表str属性;

  • type是指该属性所对应的类型,如Persondao对应的是com.aptech.dao.PersonDAO;

  • ref 是指引用的依赖对象;

  • value 当注入的不是依赖对象,而是基本数据类型时,就用value;

(2)、set注入

Set方式注入可以给指定Bean注入属性值或者依赖的对象,属性注入使用元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 子节点指定属性值.

定义一个JavaBean并赋予其Setter方法

注入各种数据类型

测试

3、注解的注入

autowire byName (按名称自动装配),会自动在容器上下文中查找,和自己对象set方法后面的值对应的beand id

使用的时需要保证所有的bean id唯一,并且这个bean需要和自动注入的属性的set方法的值一致

4、扩展的注入

(1)、常量的注入

<!-- 第一种 普通值注入 value-->
<property name="name" value="张三"/>

(2)、set方式注入

<property name="aid" value="22"></property>

(3)、构造方法注入

构造方法里的参数顺序

<constructor-arg value="值"/>

构造方法里参数的索引位置

<constructor-arg index="索引" value="值"/>

(4)、Bean注入

<!-- 第二种 Bean注入 ref-->
<property name="address" ref="address"/>

(5)、数组注入

<!-- 第三种 数组注入 -->
<property name="books">
    <!-- 数组 -->
    <array>
        <value>红楼梦</value>
        <value>水浒传</value>
        <value>西游记</value>
        <value>三国演义</value>
    </array>
</property>

(6)、List注入

<!-- 第四种 List注入 -->
<property name="hobbys">
    <list>
        <value>唱歌</value>
        <value>阅读</value>
        <value>观影</value>
    </list>
</property>

(7)、Map注入

<!-- 第五种 Map注入 -->
<property name="card">
    <map>
        <entry key="省份证" value="123456789"/>
        <entry key="银行卡" value="987654321"/>
    </map>
</property>

(8)、ull注入

<!-- 第七种 Null注入 -->
<property name="wife">
    <null/>
</property>

(9)、Properties注入

<!-- 第八种 Properties注入 -->
<property name="info">
    <props>
        <prop key="学号">20201501</prop>
        <prop key="姓名">"王浩"</prop>
        <prop key="性别">"男"</prop>
    </props>
</property>

(10)、p命令注入

注意:这里没有有参构造器

User类

public class User {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

userbeans.xml

<!-- p命名空间注入,可以直接注入属性的值:property-->
<bean id="user" class="com.User" p:name="张三" p:age="18"/>

测试类

public class mytest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
        User user = context.getBean("user",User.class);
        System.out.println(user);
    }
}

(11)、c命名注入

注意:这里有有参构造器

User类

public class User {
    private String name;
    private int age;

    public User(){

    }

    public User(String name,int age){
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

userbeans.xml

<!-- c命名空间注入,可以通过构造器注入:constructs-->
<bean id="user2" class="com.User" c:name="李四" c:age="20"/>

测试类

public class mytest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
        User user = context.getBean("user2",User.class);
        System.out.println(user);
    }
}

5、Bean的自动装配

Spring中bean有三种装配机制,分别是:

  1. 在xml中显式配置;

  2. 在java中显式配置;

  3. 隐式的bean发现机制和自动装配

Spring的自动装配的两个操作:

  1. 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;

  2. 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

Cat类

Dog类

People类

beans.xml

mytest

(1)、byName

autowire byName (按名称自动装配),会自动在容器上下文中查找,和自己对象set方法后面的值对应的beand id

使用的时需要保证所有的bean id唯一,并且这个bean需要和自动注入的属性的set方法的值一致

当一个bean节点带有 autowire byName的属性时:

  1. 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。

  2. 去spring容器中寻找是否有此字符串名称id的对象。

  3. 如果有,就取出注入;如果没有,就报空指针异常。

(2)、byType

autowire byType (按类型自动装配),会自动在容器上下文中查找,和自己对象属性类型相同bean

使用的的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致

7、使用注解

在spring配置文件中引入context文件头

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

开启属性注解支持

<context:annotation-config/>

(1)、@Autowired

  • @Autowired是按类型自动转配的,不支持id匹配。

  • 需要导入 spring-aop的包

将People中set方法去掉,使用@Autowired注解

beans.xml

(2)、@Qualifier

  • @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配

  • @Qualifier不能单独使用。

beams.xml

People

(3)、@Resource

maven配置porm.xml中未导入java注释需要的包

<dependency>  
    <groupId>javax.annotation</groupId>  
    <artifactId>jsr250-api</artifactId>  
    <version>1.0</version>  
</dependency>
  • @Resource如有指定的name属性,先按该属性进行byName方式查找装配;

  • 其次再进行默认的byName方式进行装配;

  • 如果以上都不成功,则按byType的方式自动装配。

  • 都不成功,则报异常。

People

beans.xml

8、使用注解开发

(1)、属性注入

User类

可以不用提供set方法,直接在直接名上添加@value(“值”)

@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
   @Value("秦疆")
   // 相当于配置文件中 <property name="name" value="秦疆"/>
   public String name;
}

如果提供了set方法,在set方法上添加@value(“值”);

@Component("user")
public class User {

   public String name;

   @Value("秦疆")
   public void setName(String name) {
       this.name = name;
  }
}

(2)、衍生注解

@Component三个衍生注解

为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。

  • @Controller:controller层

  • @Service:service层

  • @Repository:dao层

写上这些注解,就相当于将这个类交给Spring管理装配

(3)、作用域

所谓Bean的作用域是指spring容器创建Bean后的生存周期即由创建到销毁的整个过程。

singleton(单例模式)

在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,bean作用域范围的默认值。

prototype(原型模式)

每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。

request

每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的Spring WebApplicationContext环境。

session

同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的Spring WebApplicationContext环境。

application

限定一个Bean的作用域为ServletContext的生命周期。该作用域仅适用于web的Spring WebApplicationContext环境。

singleton

Spring默认所有Bean其作用域都是Singleton。在这样的作用域下,每一个Bean的实例只会被创建一次,而且Spring容器在整个应用程序生存期中都可以使用该实例。因此之前的代码中spring容器创建Bean后,通过代码获取的bean,无论多少次,都是同一个Bean的实例。我们可使用<bean>标签的scope属性来指定一个Bean的作用域,如下:

prototype

prototype,它代表每次获取Bean实例时都会新创建一个实例对象,类似new操作符

区别

  • singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。

  • prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收

(4)、生命周期

Bean实例生命周期的执行过程如下:

  • Spring对bean进行实例化,默认bean是单例;

  • Spring对bean进行依赖注入;

  • 如果bean实现了BeanNameAware接口,Spring将bean的名称传给setBeanName()方法;

  • 如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory实例传进来;

  • 如果bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用上下文的引用传入到bean中;

  • 如果bean实现了BeanPostProcessor接口,它的postProcessBeforeInitialization()方法将被调用;

  • 如果bean中有方法添加了@PostConstruct注解,那么该方法将被调用;

  • 如果bean实现了InitializingBean接口,spring将调用它的afterPropertiesSet()接口方法,类似的如果bean使用了init-method属性声明了初始化方法,该方法也会被调用;

  • 如果在xml文件中通过<bean>标签的init-method元素指定了初始化方法,那么该方法将被调用;

  • 如果bean实现了BeanPostProcessor接口,它的postProcessAfterInitialization()接口方法将被调用;

  • 此时bean已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁;

  • 如果bean中有方法添加了@PreDestroy注解,那么该方法将被调用;

  • 若bean实现了DisposableBean接口,spring将调用它的distroy()接口方法。同样的,如果bean使用了destroy-method属性声明了销毁方法,则该方法被调用;

本文含有隐藏内容,请 开通VIP 后查看