Spring学习:Spring的IOC注解

这篇博客详细介绍了Spring的IOC注解使用,包括常用的注解、包扫描、数据装配,以及Bean的生命周期、实例化时机、单例与多例的设定。并提供了完整的示例代码,包括接口定义、实现类、XML配置等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、简介

Spring提供了一系列的注解来替代 xml 中的配置,而在实际开发中,建议使用:注解+配置 的形式。

二、IOC注解

(一)常用的注解

常用的注解,区分组件Bean的类型,是根据Bean实现的功能不同来确定在IOC容器中是一个什么组件

注解名称说明
@Component定义Bean组件,添加到IoC容器中,不区分组件类型
@Repository表示Dao组件(区分组件)
@Service表示Service组件(区分组件)
@Controller表示Action组件(区分组件)

(二)扫描包

通过在配置文件中扫描包库,看是否存在加载了注解的类,如果类有上面表格常用的容器注解,说明此类是IOC容器的Bean,扫包可以配置多个,但这个地方需要注意,不要扫描太多,一般只扫描需要带有注解的包,因为扫包是要花时间的。具体在xml中扫描的代码示例如下:

<!-- TODO:1.扫描指定的类包,看是否存在以@Component,@Service,@Repository,@Controller开始的类注解,如果有的话,
    将其加载到IOC容器中,创建IOC的Bean,此时的Bean的名字ID以默认类名,如果在注解中设置了名字,则以命名为Bean的ID名
     扫包可以配置多个,但这个地方需要注意,不要扫描太多,一般只扫描需要带有注解的包,因为扫包是要花时间的。-->
    <context:component-scan base-package="aop3.action.impl"/>
    <context:component-scan base-package="aop3"/> <!--这行扫所aop3包下面所有的类是否包IOC容器Bean注解,需要花费更多的时间-->

(三)数据装配

注解方式的数据装配是直接使用属性进行注入,不是使用setter方法,所以可以没有setter方法.

  1. 简单数据的装配: 基本数据类型的装配(简单数据类型),是通过@value()来装配的,@Value()中的值放入的都是字符串
// TODO: 2021/6/29 Bean中属性数据装配
    // TODO: 2021/6/29 1.基本数据类型的装配(简单数据类型),是通过@value()来装配的,@Value()中的值放入的都是字符串

    @Value("hello java")
    private String username;

    @Value("20")
    private int age;

    @Value("6000")
    private int salary;

    @Value("true")
    private boolean flag;
    
    // TODO: 2021/6/29 当一个属性需要装配本地文件的时候
    @Value("classpath:aop3/aop3.properties")
    private Resource resource;
  1. 默认属性文件的装配
    // TODO: 2021/6/29 2.IOC容器中加载java自带的属性转换后置处理器,这个后置处理器将一个属性文件装配到的Resource属性中,通过解析传递给注
    // 解的值,然后再从属性文件中读取解析后值对应的内容。
    @Value("${password}")
    private String password;

在xml配置文件中,需要配置后置处理器,即在IOC容器中加载后置处理器,这里的后置处理器是Spring自还的,能解析传入的值得到相对应的值,得到的这个值是properties文件中的属性名,在这个后置处理器Bean中,传入属性文件properties文件,从而得到相对应的属性值,得新赋值给属性。具体在xml中加载属性解析后置处理器的代码如下:

 <!-- TODO: 第一种方式:基于命名空间 -->
    <context:property-placeholder location="classpath:aop3/aop3.properties"/>
    <!-- TODO:第二种方式:传统的创建Bean -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:aop3/aop3.properties"/>
    </bean>
  1. 其他Bean的装配
    一个Bean中的属性为Bean的时候,可以采取自动装配的方式来进行数据装配,装配的先后顺序为,先类型、后名字,相同类型多个,名字都不同的时候,可以指定名字。
    // TODO: 2021/6/29 3.其他自定义Bean的装配
    // TODO: 2021/6/29 1.使用@Authwired自动装配,这个地方的装配首先是依据类型(byType)进行自动装配,如果IOC容器中包含有多个相同类型的Bean
    // TODO: 2021/6/29 后面就按名字byName(按名字)进行装配 
    // TODO: 2021/6/29 按指定名字进行装配,其注解为:@Quaiifier("指定的名字")

    //    @Autowired //自动装配,这里的情形是两个相同类型Bean,两个Bean名不同,且和要装配属性名也不同,在这种情况下名都不为可以使用@Quualifier("指定的Bean名")
    //    @Qualifier("student2")
    @Resource //这也是自动装配,是依据名字byName自动从IOC窗口中找到ID指的名字和属性名一样的Bean
    private StudentImpl student;
  1. 集合的装配
    如:数组,List,Set,Map,Properties,Resource。在这个地方需要注意的时,这些类型的数据,属性名和在xml文件中定义的ID一致时,会自动装配数据。也可以指定ID的名字来装配数据,在集合中,装配数据用到的注释为:@Resource()
    下面的代码是定义在Bean中的集合等相关属性:
// TODO: 2021/6/29 4.特殊数据的装配,如:数组,List,Set,Map,Properties,Resource
    // TODO: 2021/6/29 对于集合类型的值的装配,采取的注解为:
    // TODO: 2021/6/29 在这个地方,如果属性名和xml配置中命名空间中的ID名相同的时候,会自动装配数据,
    @Resource(name = "as")
    private Integer[] array;

    @Resource(name = "list2")
    private List<StudentImpl> list;

    // TODO: 2021/6/29 下面三个数据的装配,是因为属性名和IOC容器中装配数据命名空间<util>中的ID名一样,所以会自动装配数据
    @Resource
    private Set<StudentImpl> set;
    @Resource
    private Map<StudentImpl, Class> map;
    @Resource
    private Properties properties;

下面的代码是在XML文件中,给Bean属性装配数据的代码

 <!-- TODO:五种非基本数据类型的数据,采取注解方式的数据装配 -->

    <!-- TODO:下面的配置主要是给IOC容器中的Bean,采取以注解的方式装配的属性,在这里也是采取命名空间方式来给注入值 -->
    <!-- TODO:数组装配 -->
    <util:list id="as">
        <value></value>
        <value>2</value>
        <value>3</value>
    </util:list>

    <!-- TODO:List装配,一般在类中定义的属性为泛型,指定存储到List集合中的数据类型 -->
    <util:list id="list2">
        <ref bean="newstudent"/>
        <ref bean="student2"/>
        <bean class="aop3.action.impl.StudentImpl">
            <property name="name" value="c++"/>
            <property name="age" value="30"/>
            <property name="score" value="99"/>
        </bean>
    </util:list>

    <!-- TODO:Set<>装配,也是依据泛型确定的数据类型进行装配 -->
    <util:set id="set">
        <!-- TODO:由于是set集合,是无序不可重复的,所以放入两个相同的Bean时,不入存入 -->
        <ref bean="student2"/>
        <ref bean="student2"/>
        <ref bean="student2"/>
        <bean class="aop3.action.impl.StudentImpl">
            <property name="name" value="c++"/>
            <property name="age" value="30"/>
            <property name="score" value="99"/>
        </bean>
    </util:set>

    <!-- TODO:Map<>的装配 -->
    <util:map id="map">
        <!-- TODO:Map中是键值对节点,键和值存储的数据类型两种:基本数据类型和引用数据类型,所以键值对节点有key和value,
         key-ref和value-ref之分-->
        <entry key-ref="student2" value="StudentImpl.class"/>
        <entry key-ref="newstudent" value="StudentImpl.class"/>
    </util:map>

    <!-- TODO:properties属性数据的装配 -->
    <util:properties id="properties">
        <prop key="password">123456</prop>
    </util:properties>

三、生命周期

一个Bean的生命周期,通过注解@PostConstruct在Bean装配数据后主动调用自定义的init()初始化的方法在Bean销毁前,主动调用自定义的destory()方法。

 // TODO: 2021/6/29 一个Bean的生命周期,通过注解@PostConstruct在Bean装配数据后主动调用自定义的init()初始化的方法,
    // 在Bean销毁前,主动调用自定义的destory()方法
    @PostConstruct  //装配数据后执行
    public void init() {
        System.out.println("数据装配完成后,初始化Bean");
    }
    
    @PreDestroy //Bean销毁前执行
    public void destory() {
        System.out.println("Bean销毁前,调用的方法");
    }

四、Bean实例化的时机

Bean的实例化时机,是指IOC容器中的Bean是在IOC容器形成时而形成,还是在从IOC容器中调用getBean()方法才形成。其用到的注解为:@Lazy

@Lazy //此注解决定了此Bean在IOC容器创建的时机,此注解说明是在调用getBean()方法后创建

五、Bean在IOC容器中单例和多例

在IOC容器中,一个Bean是单例还是多例可以通过注解@Scop()来设定,当值为:singleton时,为单例;当值为:prototype时,为多例。具体的代码为:

@Scope("prototype") //此注解为作用域注解,即在IOC中获得的Bean是单例的还是多例的,simple为单例,prototype为多例

六、SpringIOC注解完整示例代码

(一)创建接口及接口的实现类

  1. 接口
public interface UserAction {
}
  1. 其他类
import aop3.pos.StringToUserPropertiesEditor;
import org.springframework.stereotype.Component;

/**
 * ClassName: StudentImpl;
 * User: FWJWORK;
 * PackageName: aop3.action.impl;
 * Date:2021/6/29;
 * Time:18:43;
 * Descritpion: <br>
 */

@Component("student2")
public class StudentImpl {
    private String name;
    private int age;
    private int score;


    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;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
}

(二)将实现类定义为IOC容器中的Bean

import aop3.action.UserAction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;


import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

// TODO: 2021/6/29 通过注解定义IOC容器Bean的两种方式,第一种是以类名为Bean的ID名,第二种是自定义的名字为Bean的ID名
// TODO: 2021/6/29 同时,一个Bean类,可以区分组件类型,在用注解定义为IOC容器中的一个Bean时,
// 区分组件Bean的定义注解有:@Repository;@Service;@Contorller

@Component  //此注解声明是IOC容器中的一个Bean,通过配置文件扫描包可以创建到IOC容器中
//@Component("methonName")
@Lazy //此注解决定了此Bean在IOC容器创建的时机,此注解说明是在调用getBean()方法后创建
@Scope("prototype") //此注解为作用域注解,即在IOC中获得的Bean是单例的还是多例的,simple为单例,prototype为多例
public class UserActionImpl implements UserAction {

    // TODO: 2021/6/29 Bean中属性数据装配
    // TODO: 2021/6/29 1.基本数据类型的装配(简单数据类型),是通过@value()来装配的,@Value()中的值放入的都是字符串

    @Value("hello java")
    private String username;

    @Value("20")
    private int age;

    @Value("6000")
    private int salary;

    @Value("true")
    private boolean flag;

    // TODO: 2021/6/29 当一个属性需要装配本地文件的时候
    @Value("classpath:aop3/aop3.xml")
    private Resource resource;

    // TODO: 2021/6/29 2.IOC容器中加载java自带的属性转换后置处理器,这个后置处理器将一个属性文件装配到的Resource属性中,通过解析传递给注
    // 解的值,然后再从属性文件中读取解析后值对应的内容。
    @Value("${password}")
    private String password;
    // TODO: 2021/6/29 3.其他自定义Bean的装配
    // TODO: 2021/6/29 1.使用@Authwired自动装配,这个地方的装配首先是依据类型(byType)进行自动装配,如果IOC容器中包含有多个相同类型的Bean
    // TODO: 2021/6/29 后面就按名字byName(按名字)进行装配 
    // TODO: 2021/6/29 按指定名字进行装配,其注解为:@Quaiifier("指定的名字")

    //    @Autowired //自动装装,这里的情奖品是有两个同类型,不同名的Bean,且名都不为student
    //    @Qualifier("student2")
    @Resource //这也是自动装配,是依据名字byName自动装配
    private StudentImpl student;


    // TODO: 2021/6/29 4.特殊数据的装配,如:数组,List,Set,Map,Properties,Resource
    // TODO: 2021/6/29 对于集合类型的值的装配,采取的注解为:
    // TODO: 2021/6/29 在这个地方,如果属性名和xml配置中命名空间中的ID名相同的时候,会自动装配数据,
    @Resource(name = "as")
    private Integer[] array;

    @Resource(name = "list2")
    private List<StudentImpl> list;

    // TODO: 2021/6/29 下面三个数据的装配,是因为属性名和IOC容器中装配数据命名空间<util>中的ID名一样,所以会自动装配数据
    @Resource
    private Set<StudentImpl> set;
    @Resource
    private Map<StudentImpl, Class> map;
    @Resource
    private Properties properties;

    // TODO: 2021/6/29 一个Bean的生命周期,通过注解@PostConstruct在Bean装配数据后主动调用自定义的init()初始化的方法,
    // 在Bean销毁前,主动调用自定义的destory()方法
    @PostConstruct  //装配数据后执行
    public void init() {
        System.out.println("数据装配完成后,初始化Bean");
    }

    @PreDestroy //Bean销毁前执行
    public void destory() {
        System.out.println("Bean销毁前,调用的方法");
    }
}

(三)通过xml文件配置IOC窗口

<?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"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">

    <!-- TODO:1.扫描指定的类包,看是否存在以@Component,@Service,@Repository,@Controller开始的类注解,如果有的话,
    将其加载到IOC容器中,创建IOC的Bean,此时的Bean的名字ID以默认类名,如果在注解中设置了名字,则以命名为Bean的ID名
     扫包可以配置多个,但这个地方需要注意,不要扫描太多,一般只扫描需要带有注解的包,因为扫包是要花时间的。-->
    <context:component-scan base-package="aop3.action.impl"/>
    <context:component-scan base-package="aop3"/> <!--这行扫所aop3包下面所有的类是否包IOC容器Bean注解,需要花费更多的时间-->

    <!-- TODO: 第一种方式:基于命名空间 -->
    <context:property-placeholder location="classpath:aop3/aop3.properties"/>
    <!-- TODO:第二种方式:传统的创建Bean -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:aop3/aop3.properties"/>
    </bean>

    <!-- TODO:再创建一个StudentImpl类Bean在IOC容器中,一个是用注解@Component创建的,目的是用于自动配置,自动配置都是先按类型,再按名字 -->
    <bean id="newstudent" class="aop3.action.impl.StudentImpl">
        <property name="name" value="python"/>
        <property name="age" value="20"/>
        <property name="score" value="100"/>
    </bean>


    <!-- TODO:五种非基本数据类型的数据,采取注解方式的数据装配 -->

    <!-- TODO:下面的配置主要是给IOC容器中的Bean,采取以注解的方式装配的属性,在这里也是采取命名空间方式来给注入值 -->
    <!-- TODO:数组装配 -->
    <util:list id="as">
        <value></value>
        <value>2</value>
        <value>3</value>
    </util:list>

    <!-- TODO:List装配,一般在类中定义的属性为泛型,指定存储到List集合中的数据类型 -->
    <util:list id="list2">
        <ref bean="newstudent"/>
        <ref bean="student2"/>
        <bean class="aop3.action.impl.StudentImpl">
            <property name="name" value="c++"/>
            <property name="age" value="30"/>
            <property name="score" value="99"/>
        </bean>
    </util:list>

    <!-- TODO:Set<>装配,也是依据泛型确定的数据类型进行装配 -->
    <util:set id="set">
        <!-- TODO:由于是set集合,是无序不可重复的,所以放入两个相同的Bean时,不入存入 -->
        <ref bean="student2"/>
        <ref bean="student2"/>
        <ref bean="student2"/>
        <bean class="aop3.action.impl.StudentImpl">
            <property name="name" value="c++"/>
            <property name="age" value="30"/>
            <property name="score" value="99"/>
        </bean>
    </util:set>

    <!-- TODO:Map<>的装配 -->
    <util:map id="map">
        <!-- TODO:Map中是键值对节点,键和值存储的数据类型两种:基本数据类型和引用数据类型,所以键值对节点有key和value,
         key-ref和value-ref之分-->
        <entry key-ref="student2" value="StudentImpl.class"/>
        <entry key-ref="newstudent" value="StudentImpl.class"/>
    </util:map>

    <!-- TODO:properties属性数据的装配 -->
    <util:properties id="properties">
        <prop key="password">123456</prop>
    </util:properties>

</beans>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值