Spring注解驱动开发_组件注册-@Configuration&@Bean给容器中注册组件

一、Spring IoC 和 DI

IoC(Inversion of Control):控制反转,是一种设计思想,即将对象的控制权交由Spring进行管理,在以往程序中,当我们需要使用某一个对象时,是由我们自己在程序中通过 new 进行创建的,而在 Spring 中,Spring 提供了 IoC 容器来对对象的创建进行管理。
DI(Dependency Injection):提及 IoC,就必须提到另一个概念依赖注入,在以往的程序中,对象的属性以及对象之间的依赖是由我们自己进行控制和注入的,而 IoC 容器则会帮我们查找,并注入属性以及依赖对象。
IoC 容器:Spring既然要对对象进行统一管理,那么就必须要有一个地方去存储这些对象,而这个地方就被称之为 Spring 的 IoC 容器。

  • BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用。
  • ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用。

二、通过 XML 配置文件注入 Bean

pom文件

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.2.6.RELEASE</version>
</dependency>

创建实体类 Person

package org.example.pojo;

public class Person {
    private String name;
    private String age;


    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

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

    public Person() {
    }

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

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

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.xsd">

    <bean id="person" class="org.example.pojo.Person">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="20"></property>
    </bean>
</beans>

测试方法:

package org.example.test;

import org.example.pojo.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmlMainTest {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring-beans.xml");
        Person person = (Person) ac.getBean("person");
        System.out.println(person);
    }
}

测试结果如下:
在这里插入图片描述

三、通过注解方式注入 Bean

定义配置类

package org.example.config;

import org.example.pojo.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MainConfig {

    @Bean
    public Person person(){
        return new Person("lis", "25");
    }
}

测试方法

package org.example.test;

import org.example.config.MainConfig;
import org.example.pojo.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AnnotationMainTest {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig.class);
        Person person = (Person) ac.getBean("person");
        System.out.println(person);
    }
}

测试结果:
在这里插入图片描述

四、@Scope 注解设置组件作用域

4.1 @Scope 注解介绍

@Scope 注解需与 @Bean 注解配合使用,其作用与 xml 配置文件中 bean 标签的属性 scope 一样。

<bean id="person" class="org.example.pojo.Person" scope="singleton"></bean>

@Scope 注解:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {

	// 与 scopeName 属性相同,作用域类型
	@AliasFor("scopeName")
	String value() default "";

	// 作用域名,同 value,共四种类型
	@AliasFor("value")
	String scopeName() default "";

	ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;

}

@Scope 注解的 value 属性共有四种类型,分别为:

  • ConfigurableBeanFactory.SCOPE_PROTOTYPE, 多实例
  • ConfigurableBeanFactory.SCOPE_SINGLETON, 单实例(默认值)
  • org.springframework.web.context.WebApplicationContext.SCOPE_REQUEST, 同一次请求创建一个实例
  • org.springframework.web.context.WebApplicationContext.SCOPE_SESSIO, 同一个session创建一个实例

4.2 具体使用

配置类:

package org.example.config;

import org.example.pojo.Person;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(value = "org.example")
public class MainConfig {

    @Scope
    @Bean("person")
    public Person person(){
    	System.out.println("向容器中添加Person.......");
        return new Person("lis", "25");
    }
}

测试方法:

@Test
public void testComponentScan(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig.class);
}

测试结果:
在这里插入图片描述
这说明单实例 bean,在 IoC 容器启动时就会调用方法创建对象并将对象注入到 IoC 容器中。

如果我们多次从 IoC 容器中获取单实例 bean,那么获取到的 bean 实际上是同一个,测试方法如下:

@Test
public void testScope(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig2.class);
    Object person1 = ac.getBean("person");
    Object person2 = ac.getBean("person");
    System.out.println(person1 == person2);
}

测试结果如下,可以看出两次获取到的 Person 对象,实际上是同一个,由于 IoC 容器启动时就会调用方法创建对象并将对象注入到 IoC 容器中,所以第二次获取 Person 的时候,其实是直接从 IoC 容器中获取的,所以控制台只输出了一次”向容器中添加Person…“,比较结果也返回了true。
在这里插入图片描述
我们来看下多实例情况下,bean 的获取情况,将注解 @Scope 的 value 属性改为 ConfigurableBeanFactory.SCOPE_PROTOTYPE,配置类代码如下:

package org.example.config;

import org.example.pojo.Person;
import org.springframework.context.annotation.*;

@Configuration
@ComponentScan(value = "org.example")
public class MainConfig2 {

    @Scope("prototype")
    @Bean("person")
    public Person person(){
        System.out.println("向容器中添加Person.......");
        return new Person("lis", "25");
    }
}

测试代码:

@Test
public void testScope(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig2.class);
    System.out.println("容器创建完成。。。。。。。。。。。。");
    Object person1 = ac.getBean("person");
    Object person2 = ac.getBean("person");
    System.out.println(person1 == person2);

}

测试结果:
在这里插入图片描述
分析:
可以看出,IoC 容器启动后并不会去调用方法创建对象放在容器中,而是每次在获取的时候才回去创建。

五、@Lazy 懒加载注解

先来看下懒加载 @Lazy 注解的详细定义:

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lazy {
	// 是否开启懒加载功能
	boolean value() default true;

}

该注解可以加载 类、方法、构造器、参数以及属性上。只有一个 value 属性,表示是否开启懒加载,默认为 true,即默认是开启懒加载的。

验证懒加载,配置类如下:

package org.example.config;

import org.example.pojo.Person;
import org.springframework.context.annotation.*;

@Configuration
@ComponentScan(value = "org.example")
public class MainConfig2 {
    @Lazy
    @Bean("person")
    public Person person(){
        System.out.println("向容器中添加Person.......");
        return new Person("lis", "25");
    }
}

测试方法:

@Test
public void testScope(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig2.class);
}

测试结果:
在这里插入图片描述
可以看出,此时懒加载已经起到了效果,IoC 容器启动时,并未创建 Person 实例,如果创建成功,则会在控制台输出”向容器中添加Person…“
修改下测试方法,如下:

@Test
public void testScope(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig2.class);
    System.out.println("容器创建完成。。。。。。。。。。。。");
    Object person1 = ac.getBean("person");
    Object person2 = ac.getBean("person");
    System.out.println(person1 == person2);

}

测试结果:
在这里插入图片描述
当我们第一次获取 Bean 时,容器创建了对象,并将该对象存放到了容器中。

总结

  • @Configuration:该注解用于类上,表示该类为一个配置类,对应 Spring 的 xml 配置文件。
  • @Bean:可用在方法上,表示向容器中注册一个 Bean,类型为返回值类型,Bean 名默认为方法名。对应 xml 配置文件中的 <bean></bean>
<bean id="person" class="org.example.pojo.Person"></bean>
  • 通过注解 @Bean 注册实例时,在测试代码中,如果要获取容器,可以通过构造方法 public AnnotationConfigApplicationContext(Class<?>... componentClasses),将配置类传入即可,可传入多个配置类。
ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig.class);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值