Spring-SpringIoC-注解

Spring-SpringIoC-注解

xml配置组件到IoC容器的方式十分麻烦,我们可以在组件中使用注解的方式将组件添加到IoC容器中

我们可以通过配置其value属性的形式完成对id值的修改,value= 可缺省不写

注:使用注解添加组件到IoC时,组件默认的id值会直接使用类名的首字母小写形式

注解说明
@Component该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如 Service 层、Dao 层等。 使用时只需将该注解标注在相应类上即可。
@Repository该注解用于将数据访问层(Dao 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Service该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Controller该注解通常作用在控制层(如SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

Repository中文释义:存储库

注:三层中有自己特有的注解,component更多的是将工具类或者别的组件放入IoC容器中,这四个注解在功能上没有任何区别


配置扫描包

在标记注解之后,我们还要在配置文件中增加被容器扫描的包

在spring配置文件中,我们使用context:component-scan标签进行扫描

  • base-package:此属性用以配置被扫描的包,可以填写多个包名用逗号隔开,包中子包和所有类都会被递归扫描
<context:component-scan base-package="com.xiaobai.ioc_01"/>

我们在软编码jdbc配置文件时,使用context:property-placeholder标签导入了jdbc.properties


context:exclude-filter

在使用context:component-scan标签时,可以使用其子标签context:exclude-filter进行包的排除

  • type:排除的类型
  • expression:排除具体的类
<context:component-scan base-package="com.xiaobai">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

以上代码就是,使用spring接管了com.xiaobai包下所有带注解的组件,但排除注解为Repository的组件


context:include-filter

在使用context:component-scan标签时,为其添加属性use-default-filters为false,指定包不生效

再使用其子标签context:include-filter进行指定包的扫描

<context:component-scan base-package="com.xiaobai" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

以上代码就是,spring不扫描com.xiaobai包下所有带注解的组件,只扫描注解为Repository的组件


周期方法

与xml配置周期方法的方式大同小异,使用注解即可配置生命周期方法

  • @PostConstrct:指定初始化方法
  • @ProDestroy:指定销毁方法

注:这两个注解必须要导入javax.annotation依赖,才可以使用
注:这个依赖已经更新为jakarta.annotation依赖,javax是过去式了

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class JavaBean {

    @PostConstruct
    public void init(){

    }

    @PreDestroy
    public void destroy(){

    }
}

作用域配置

与xml配置作用域方式大同小异,使用注解可配置组件的作用域

  • @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON):配置单例作用域(默认值)
  • @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE):配置多例作用域

具体的作用域信息可在 笔记 -> Spring-SpringIoC -> 组件的作用域和周期方法 -> 作用域 找到

@Component
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) //单例 默认值
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //多例
public class JavaBean {
 ……
}

DI

@AutoWired

与xml配置DI的方式不同,注解配置DI的方式是使用@AutoWired实现自动装配

public class UserController {
    @Autowired
    private UserService userService;
}

@Autowired注解会在IoC容器中寻找组件,寻找到符合UserService接口的实现类(或者类本身),就将组件对象自动装配到此属性中

所以,@Autowired注解是直接对属性进行的操作,不需要有setter就可以实现

这个注解不止可以加在属性上,也可以加在构造方法或setter方法上,实现自动装配

在实际开发当中,我们最常使用的就是Autowired自动装配到属性 😊


佛系装配

自动装配时,@AutoWired注解的required值默认为true,也就是要求有对应的接口实现类来装配

而我们可以手动设置required值为false,则不强制要求有对应的接口实现类来装配

@Autowired(required = false)

但如果有调用容器,则会报空指针异常!!!!

所以不推荐使用佛系装配,除非你装配的属性不会被使用


@Qualifier

以上的自动装配情况有一个前提,这一个属性只对应一个组件,即根据接口的属性类型只查找到一个接口的实现类

当根据属性类型查找到多个组件时,再去通过属性名找组件

那如果接口下有两个实现类,我们也可以通过成员属性名的方式来进行区分

  • 方式1:将成员属性名改成实现类的名字,在自动装配时会根据这个属性名去找实现类组件对象进行装配(更改需求)
  • 方式2:将组件id值改成接口的名字的首字母小写的名字,在自动装配时也会根据属性名找到被更改的组件ID,进行装配(更改供给)

这两个方案都不够好,IoC容器提供了一个新的注解@Qualifier来解决此问题

qualifier中文释义:入围者

接口的属性值value可以指定组件对象进行装配,必须配合Autowired进行使用,value可以省略

public class UserController {
    @Autowired
    @Qualifier("userServiceImpl")
    private UserService userService;
}

@Resource

JSR(Java Specification Requests)是Java平台标准化进程中的一种技术规范,而JSR注解是其中一部分重要的内容

JSR-250提供了@Resource注解,这个注解由java提供,由spring实现

注:这个注解也必须要导入jakarta.annotation依赖,才可以使用

@Resource注解 = @Autowired注解 + @qualifire注解

它提供了一个属性name,作用与@qualifire注解的属性value相同

public class UserController {
    @Resource(name = "userServiceImpl")
    private UserService userService;
}

@Value

基本数据类型也可以通过注解的方式来赋值,使用@Value注解即可

public class JavaBean {
    @Value("xiaobai")
    String name;
}

我们也可以使用properties外部文件,在spring配置文件中使用context加载配置文件后,在注解里使用${}获取值赋值给属性

jdbc.user=root
jdbc.password=Zhuwenxue2002
<context:component-scan base-package="com.xiaobai.ioc_03"/>

<context:property-placeholder location="classpath:jdbc.properties"/>
@Component
public class JavaBean {
    @Value("${jdbc.username}")
    String username; // root

    @Value("${jdbc.password}")
    String userPwd; // Zhuwenxue2002
}

我们可以在使用:默认值语法来为数据添加默认值

@Component
public class JavaBean {
    @Value("${jdbc.username:root}")
    String username;
}

以上代码为:当jdbc.username为空时,username的值为默认值root


xml

当使用注解替代xml之后,xml的作用就变得更精简了

  • 使用<context:component-scan base-package=""/>标签配置扫描包
  • 使用<context:property-placeholder location=""/>引入外部的配置文件
    • location属性中的classpath表示相对路径,在项目中查找资源文件,再查找jar包
  • 第三方类的IoC配置

注解也没办法将第三方jar包放到IoC容器,也无法为这个jar包实现DI

比如之前我们学习的Druid和JdbcTemplate使用

<context:property-placeholder location="classpath:jdbc.properties"/>

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="${jdbc.url}"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>
    
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
	<property name="dataSource" ref="dataSource"/>
</bean>

我们无法在Druid和JdbcTemplate添加注解,将其放入IoC容器

也无法为JdbcTemplate配置@Autowired注解,让其实现自动注入连接池

所以目前来说,我们只能使用xml完成第三方类的配置

**当然,第三方类也是被放入IoC容器中,在Dao使用JdbcTemplate时也是可以直接使用@Automired自动装配的方式 ** 😐