spring揭秘06-Autowired自动绑定依赖及组件自动扫描

news2024/11/17 1:36:08

文章目录

  • 【README】
  • 【1】基于xml配置文件版本的自动绑定
    • 【1.1】基于xml配置文件版本的自动绑定代码示例
  • 【2】基于注解版本的自动绑定
    • 【2.1】根据类型匹配的注解版自动绑定@Autowired
    • 【2.2】根据名称匹配的注解版自动绑定@Autowired+@Qualifier
      • 【2.2.1】 示例代码
    • 【2.3】关于@Primary注解的补充
    • 【2.3】关于context:annotation-config元素
    • 【2.4】JSR250注解
      • 【2.4.1】 @Resource注解标注依赖注入关系代码
      • 【2.4.2】@PostConstruct 与 @PreDestroy注解
    • 【2.5】 \<context:component-scan>开启spring组件扫描
      • 【2.5.1】开启组件扫描的自动绑定代码示例
  • 【3】小结
  • 【补充】 JSR250

【README】

本文总结自《spring揭秘》,作者王福强,非常棒的一本书,墙裂推荐;

1)spring自动绑定对象间依赖关系: 指的是不用明确指定每一个bean与被依赖bean之间的依赖关系,太繁琐; 而是通过一种约定方式来指定依赖关系,如通过名称,bean类型,构造器等约定方式来指定; 通过名称或类型等约定方式指定bean之间的依赖关系称自动绑定

2)spring容器自动绑定对象间依赖关系的方式有2种,如下:

  • 方式1: 基于xml配置文件版本的自动绑定,自动绑定策略通过设置 beans元素的 default-autowire属性 或 bean元素的autowire属性来配置;
  • 方式2: 基于java注解版本的自动配置;

【1】基于xml配置文件版本的自动绑定

1)基于xml配置文件版本的自动绑定,自动绑定策略通过设置 beans元素的 default-autowire属性 或 bean元素的autowire属性来配置

2)default-autowire属性值或autowire属性值的可选项:

  • no: 不开启自动绑定;(默认不开启)
  • byname: 通过bean名称来自动绑定; 针对 bean property 的自动绑定,要有setter方法设置property属性;
  • byType: 通过bean类型来自动绑定;针对 bean property 的自动绑定, 要有setter方法设置property属性;
  • constructor: 通过构造器来自动绑定;针对构造方法参数的类型进行自动绑定;显然,constructor实际上是byType类型的自动绑定(但不需要setter方法);
  • autodetect: 通过自动检测来自动绑定;是byType与constructor的结合体; 如果对象拥有默认无参构造器,则优先考虑byType的自动绑定模式(因为构造器没有参数,也就没法使用构造器绑定);如果对象有有参构造器,则使用constructor自动绑定; 如果通过构造器注入依赖关系后还有其他属性没有绑定,最后容器还是会使用byType对剩下的属性进行自动绑定;

3)自动绑定补充:

  • 手工明确指定的绑定关系 优先级高于 自动绑定模式;
  • 自动绑定可以应用到除开原生类型 ,string类型及 Classes类型(包括三者的数组)以外的对象类型

【1.1】基于xml配置文件版本的自动绑定代码示例

1)应用场景: 对于DDD领域驱动设计,其有4层,包括表现层,应用层,领域层,基础设施层;

  • 表现层: 本文用main方法表示;

  • 应用层: 本文用 appService 表示;采用构造器constructor绑定; 底层使用setter注入;

  • 领域层: 本文用 DomainService 表示;采用byType绑定; 底层使用setter注入;

  • 基础设置层:本文用dao表示;采用byName绑定, 有setter方法;

  • 防腐层support: 在业务模型与技术模型之间,即应用层或领域层与基础设施层之间(**作用:**技术模型底层做改造,仅防腐层改动代码,上游的应用层与领域层不修改代码);

【AutoWireXmlConfMain】xml配置文件自动绑定main

public class AutoWireXmlConfMain {
    public static void main(String[] args) {
        ApplicationContext container = new ClassPathXmlApplicationContext("classpath:chapter06/beans0601autowirebasedxml.xml");
        container.getBean(RoomBookAppService.class).book("基于xml配置文件的自动绑定房间01", "张三");
    }
}

【beans0601autowirebasedxml.xml】 beans元素的default-autowire属性设置为byName, bean元素的autowire属性设置为 constructor,byType, byName

<?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"
        default-autowire="byName">

    <bean id="roomBookAppService" class="com.tom.springnote.chapter05.chapter0504.RoomBookAppService" autowire="constructor" />
    <bean id="roomBookDomainService" class="com.tom.springnote.chapter05.chapter0504.RoomBookDomainService" autowire="byType" />
    <bean id="roomBookSupportImpl" class="com.tom.springnote.chapter05.chapter0504.RoomBookSupportImpl" autowire="byName" />
    <bean id="roomBookDAO" class="com.tom.springnote.chapter05.chapter0504.RoomBookDAO" />
</beans>

【RoomBookAppService】应用层, 通过构造器绑定

public class RoomBookAppService {

    private RoomBookDomainService roomBookDomainService;

    public RoomBookAppService(RoomBookDomainService roomBookDomainService) {
        this.roomBookDomainService = roomBookDomainService;
    }

    public void book(String roomId, String customer) {
        roomBookDomainService.book(roomId, customer);
    }
}

【RoomBookDomainService】领域层,通过byType绑定,必须要有setter方法;( 属性名称叫roomBookSupport,但xml中配置的bean名称为roomBookSupportImpl,通过byName无法绑定

public class RoomBookDomainService {

    private IRoomBookSupport roomBookSupport;

    public void book(String roomId, String customer) {
        roomBookSupport.saveRoomBookInf(roomId, customer);
    }

    public void setRoomBookSupport(IRoomBookSupport roomBookSupport) {
        this.roomBookSupport = roomBookSupport;
    }
}

【IRoomBookSupport】防腐层接口

public interface IRoomBookSupport {

    void saveRoomBookInf(String roomId, String customer);
}

【RoomBookSupportImpl】防腐层实现类 ; 通过byName绑定 ;必须要有setter方法 ;

public class RoomBookSupportImpl implements IRoomBookSupport {

    private RoomBookDAO roomBookDAO;

    @Override
    public void saveRoomBookInf(String roomId, String customer) {
        roomBookDAO.insertRoomBook(roomId, customer);
    }

    public void setRoomBookDAO(RoomBookDAO roomBookDAO) {
        this.roomBookDAO = roomBookDAO;
    }
}

【RoomBookDAO】基础设施层; 无需绑定对象依赖关系(因为没有依赖),仅注册bean到spring容器即可;

public class RoomBookDAO {

    public void insertRoomBook(String roomId, String customer) {
        System.out.printf("RoomBookDAO: 插入订房信息成功:roomId=[%s], customer=[%s]\n", roomId, customer);
    }
}

【打印日志】

RoomBookDAO: 插入订房信息成功:roomId=[基于xml配置文件的自动绑定房间01], customer=[张三]

【2】基于注解版本的自动绑定

【2.1】根据类型匹配的注解版自动绑定@Autowired

1)@Autowired是基于注解版本的自动绑定的核心注解, spring容器根据@Autowired标注的位置为当前类注入依赖;

2)@Autowired注解的标注位置:

  • 标注类属性property;优先使用 byName自动绑定,若绑定失败,则使用 byType 自动绑定;
  • 标注构造方法定义;使用byType绑定;即根据构造器参数类型,来决定把什么样的依赖对象注入给当前对象;
  • 标注普通方法定义; @Autowired不仅标注setter方法,还可以标注任意名称的方法,只要该方法定义了被注入的参数;

3)案例场景: 房间预订服务;

【AutoWireBasedAnnotationMain】基于注解的自动绑定main

public class AutoWireBasedAnnotationMain {
    public static void main(String[] args) {
        ApplicationContext container = new ClassPathXmlApplicationContext("classpath:chapter06/beans0601autowirebasedannotation.xml");
        container.getBean(AnnotationBookAppService.class).book("基于注解的自动绑定房间01", "张三");
    }
}

【beans0601autowirebasedannotation.xml】 若使用 @Autowired,必须注册 AutowiredAnnotationBeanPostProcessor

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

    <!-- 注册AutowiredAnnotationBeanPostProcessor, 用于检查是否有@Autowired标注的位置以便注入依赖 【若使用 @Autowired,必须注册该BeanPostProcessor-->
    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />

    <!-- 注册bean,依赖关系由 @Autowired 标注,spring容器根据标注位置绑定依赖 -->
    <bean id="roomBookAppService" class="com.tom.springnote.chapter06.autowirebaseannotation.RoomBookAppService" />
    <bean id="roomBookDomainService" class="com.tom.springnote.chapter06.autowirebaseannotation.RoomBookDomainService" />
    <bean id="roomBookSupportImpl" class="com.tom.springnote.chapter06.autowirebaseannotation.RoomBookSupportImpl" />
    <bean id="roomDAO" class="com.tom.springnote.chapter06.autowirebaseannotation.RoomDAO" />
    <bean id="hotelDAO" class="com.tom.springnote.chapter06.autowirebaseannotation.HotelDAO" />

</beans>

【RoomBookAppService】 应用层:@Autowired标注构造器 (byType的自动绑定

public class RoomBookAppService {

    private RoomBookDomainService bookDomainService;

    @Autowired
    public RoomBookAppService(RoomBookDomainService bookDomainService) {
        this.bookDomainService = bookDomainService;
    }

    public void book(String roomId, String customer) {
        bookDomainService.book(roomId, customer);
    }
}

【RoomBookDomainService】 领域层: @Autowired标注属性 (byType的自动绑定

public class RoomBookDomainService {

    @Autowired
    private IRoomBookSupport bookSupport;

    public void book(String roomId, String customer) {
        bookSupport.saveRoomBookInf(roomId, customer);
    }

    public void setBookSupport(IRoomBookSupport bookSupport) {
        this.bookSupport = bookSupport;
    }
}

【IRoomBookSupport】防腐层接口

public interface IRoomBookSupport {

    void saveRoomBookInf(String roomId, String customer);
}

【RoomBookSupportImpl】防腐层:.@Autowired标注setter方法 ,标注普通方法 (byType的自动绑定

public class RoomBookSupportImpl implements IRoomBookSupport {
    private RoomDAO bookDAO;
    private HotelDAO hotelDAO;

    @Override
    public void saveRoomBookInf(String roomId, String customer) {
        if (!hotelDAO.IfAuthLegal(customer)) {
            System.out.println("权限校验失败");
            return;
        }
        System.out.println("权限校验成功");
        bookDAO.insertRoomBook(roomId, customer);
    }

    @Autowired
    public void setBookDAO(RoomDAO bookDAO) {
        this.bookDAO = bookDAO;
    }

    @Autowired
    public void injectHotelDAO(HotelDAO hotelDAO) {
        this.hotelDAO = hotelDAO;
    }
}

【HotelDAO】

public class HotelDAO {

    public boolean IfAuthLegal(String customer) {
        System.out.printf("HotelDAO#IfAuthLegal(): [%s]权限校验合法", customer);
        return true;
    }
}

【RoomDAO】

public class RoomDAO {

    public void insertRoomBook(String roomId, String customer) {
        System.out.printf("RoomDAO#insertRoomBook(): 插入订房信息成功:roomId=[%s], customer=[%s]\n", roomId, customer);
    }
}

【打印日志】

HotelDAO#IfAuthLegal(): [张三]权限校验合法权限校验成功
RoomDAO#insertRoomBook(): 插入订房信息成功:roomId=[基于注解的自动绑定房间01], customer=[张三]


【2.2】根据名称匹配的注解版自动绑定@Autowired+@Qualifier

1)背景: 若一个接口有2个或多个实现类,如实例A与B ; 而@Autowired 注解是通过byType自动绑定,无法确认注入实例A还是实例B;

2)解决方法: 引入 @Qualifier注解, 解决@Autowired无法注入有多个类型匹配的bean的问题;

  • @Qualifier注解:实际上是 byName自动绑定注解版,指定注入给定name的bean;
  • @Qualifier注解 只能与 @Autowired结合使用,不能单独使用;

【2.2.1】 示例代码

业务场景: 酒店预订助手接口有2个实现类, 包括 万达酒店预定助手实现类, 希尔顿酒店预定助手实现类; 通过 @Qualifier注解指定bean名称并注入name匹配的bean;

【AutowireQualifierAnnotationMain】基于@Autowired与@Qualifier注解自动绑定main

public class AutowireQualifierAnnotationMain {
    public static void main(String[] args) {
        ApplicationContext container = new ClassPathXmlApplicationContext("classpath:chapter06/beans0601autowirequlifierannotation.xml");
        container.getBean(AutowireQualifierBookAppService.class).book("@Autowired与@Qualifier注解的自动绑定01", "张三");
    }
}

【beans0601autowirequlifierannotation.xml】 新增 <context:annotation-config/> 元素, 以激活 @Autowired 和 @Qualifier 注解

<?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.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <!-- 注册 AutowiredAnnotationBeanPostProcessor, 用于检查是否有@Autowired标注的位置以便注入依赖
    AutowiredAnnotationBeanPostProcessor 激活 @Autowired 注解 -->
    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />

    <!-- 注册bean -->
    <bean id="bookAppService" class="com.tom.springnote.chapter06.autowiredqualifierannotation.AutowireQualifierBookAppService" />
    <bean id="bookDomainService" class="com.tom.springnote.chapter06.autowiredqualifierannotation.AutowireQualifierBookDomainService" />
    <bean id="bookDomainService2" class="com.tom.springnote.chapter06.autowiredqualifierannotation.AutowireQualifierBookDomainService" />
    <bean id="hiltonRoomBookSupportImpl" class="com.tom.springnote.chapter06.autowiredqualifierannotation.HiltonRoomBookSupportImpl" />
    <bean id="wandaRoomBookSupportImpl" class="com.tom.springnote.chapter06.autowiredqualifierannotation.WandaRoomBookSupportImpl" />
    <bean id="roomDAO" class="com.tom.springnote.chapter06.autowiredqualifierannotation.RoomDAO" />
    <bean id="roomDAO2" class="com.tom.springnote.chapter06.autowiredqualifierannotation.RoomDAO" />
    <bean id="hotelDAO" class="com.tom.springnote.chapter06.autowiredqualifierannotation.HotelDAO" />
    <bean id="hotelDAO2" class="com.tom.springnote.chapter06.autowiredqualifierannotation.HotelDAO" />

</beans>

【AutowireQualifierBookAppService】 ( 构造器新增 @Quailfier注解

public class AutowireQualifierBookAppService {

    private AutowireQualifierBookDomainService annotationBookDomainService;

    @Autowired
    public AutowireQualifierBookAppService(@Qualifier("bookDomainService2") AutowireQualifierBookDomainService bookDomainService) {
        this.annotationBookDomainService = bookDomainService;
    }

    public void book(String roomId, String customer) {
        annotationBookDomainService.book(roomId, customer);
    }
}

【AutowireQualifierBookDomainService】( 属性上新增 @Quailfier注解

public class AutowireQualifierBookDomainService {

    @Autowired
    @Qualifier("hiltonRoomBookSupportImpl")
    private IAutowireQualifierBookSupport bookSupport;

    public void book(String roomId, String customer) {
        bookSupport.saveRoomBookInf(roomId, customer);
    }
}

【IAutowireQualifierBookSupport】

public interface IAutowireQualifierBookSupport {

    void saveRoomBookInf(String roomId, String customer);
}

【HiltonRoomBookSupportImpl】 ( setter方法与普通方法上新增 @Quailfier注解

public class HiltonRoomBookSupportImpl implements IAutowireQualifierBookSupport {
    private RoomDAO bookDAO;
    private HotelDAO hotelDAO;

    @Override
    public void saveRoomBookInf(String roomId, String customer) {
        System.out.println("希尔顿酒店预订助手");
        if (!hotelDAO.IfAuthLegal(customer)) {
            System.out.println("权限校验失败");
            return;
        } 
        System.out.println("权限校验成功");
        bookDAO.insertRoomBook(roomId, customer);
    }

    @Autowired
    public void setBookDAO(@Qualifier("roomDAO") RoomDAO bookDAO) {
        this.bookDAO = bookDAO;
    }

    @Autowired
    public void injectHotelDAO(@Qualifier("hotelDAO") HotelDAO hotelDAO) {
        this.hotelDAO = hotelDAO;
    }
}

【WandaRoomBookSupportImpl】 ( setter方法与普通方法上新增 @Quailfier注解

public class WandaRoomBookSupportImpl implements IAutowireQualifierBookSupport {
    private RoomDAO bookDAO;
    private HotelDAO hotelDAO;

    @Override
    public void saveRoomBookInf(String roomId, String customer) {
        System.out.println("万达酒店预订助手");
        if (!hotelDAO.IfAuthLegal(customer)) {
            System.out.println("权限校验失败");
            return;
        }
        System.out.println("权限校验成功");
        bookDAO.insertRoomBook(roomId, customer);
    }

    @Autowired
    public void setBookDAO(@Qualifier("roomDAO2") RoomDAO bookDAO) {
        this.bookDAO = bookDAO;
    }

    @Autowired
    public void injectHotelDAO(@Qualifier("hotelDAO2") HotelDAO hotelDAO) {
        this.hotelDAO = hotelDAO;
    }
}

【打印日志】

希尔顿酒店预订助手
HotelDAO#IfAuthLegal(): [张三]权限校验合法
权限校验成功
RoomDAO#insertRoomBook(): 插入订房信息成功:roomId=[基于注解的自动绑定房间01], customer=[张三]

【2.3】关于@Primary注解的补充

@Primary注解: 标注的类的bean实例化后, 若该类下有多个实例化的bean,则优先使用 被Primary标注的那个bean;

【PdfFileReader】FileReader子类1

package basic.ioc.wiring.finetune;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

@Primary
@Component
public class PdfFileReader implements FileReader {

  @Override
  public void print() {
    System.out.println("Inside PdfFileReader");
  }
}

【WordFileReader】FileReader子类2

package basic.ioc.wiring.finetune;
import org.springframework.stereotype.Component;

@Component
public class WordFileReader implements FileReader {

  @Override
  public void print() {
    System.out.println("Inside WordFileReader");
  }
}

【FineTuneAutowiring】Primary注解测试案例入口

package basic.ioc.wiring.finetune;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

@SpringJUnitConfig(ConfigWiring.class)
public class FineTuneAutowiring {

  @Autowired
  private FileReader fileReader;

  @Test
  public void testFileReader() {
    Assert.assertNotNull(fileReader);
    Assert.assertEquals(fileReader.getClass(), PdfFileReader.class);
  }
}

因为 PdfFileReader 被@Primary注解标注, 所以业务bean#FineTuneAutowiring通过 @Autowired自动绑定 FileReader实例时,优先选择PdfFileReader示例进行绑定;

【2.3】关于context:annotation-config元素

1)<context:annotation-config /> 可以激活多个注解以便在class中被探测到: 激活的注解清单如下:

  • @Required, @Autowired
  • JSR 250定义的注解 @PostConstruct, @PreDestroy and @Resource ;
  • JAX-WS’s @WebServiceRef
  • EJB 3’s @EJB
  • JPA’s @PersistenceContext and @PersistenceUnit

或者你也可以选择注入这些注解对应的BeanPostProcessor ;

2)context:annotation-config 注册的BeanPostProcessor清单如下: 参见: https://docs.spring.io/spring-framework/reference/core/beans/annotation-config.html

  • ConfigurationClassPostProcessor
  • AutowiredAnnotationBeanPostProcessor
  • CommonAnnotationBeanPostProcessor
  • PersistenceAnnotationBeanPostProcessor
  • EventListenerMethodProcessor

3) 我们可以这样理解:因为context:annotation-config 注册了多个BeanPostProcessor到spring容器,这些BeanPostProcessor可以扫描注解标注的位置,以此自动绑定相应依赖注入;即 注册BeanPostProcessor,间接激活了自动绑定的注解

4)所以 beans0601autowirequlifierannotation.xml中可以删除 AutowiredAnnotationBeanPostProcessor 这个BeanPostProcessor的注入配置;因为 context:annotation-config 激活了对应的BeanPostProcessor;

删除AutowiredAnnotationBeanPostProcessor注入配置后xml如下

【beans0601autowirequlifierannotation.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.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <!-- 注册bean -->
    <bean id="bookAppService" class="com.tom.springnote.chapter06.autowiredqualifierannotation.AutowireQualifierBookAppService" />
    <bean id="bookDomainService" class="com.tom.springnote.chapter06.autowiredqualifierannotation.AutowireQualifierBookDomainService" />
    <bean id="bookDomainService2" class="com.tom.springnote.chapter06.autowiredqualifierannotation.AutowireQualifierBookDomainService" />
    <bean id="hiltonRoomBookSupportImpl" class="com.tom.springnote.chapter06.autowiredqualifierannotation.HiltonRoomBookSupportImpl" />
    <bean id="wandaRoomBookSupportImpl" class="com.tom.springnote.chapter06.autowiredqualifierannotation.WandaRoomBookSupportImpl" />
    <bean id="roomDAO" class="com.tom.springnote.chapter06.autowiredqualifierannotation.RoomDAO" />
    <bean id="roomDAO2" class="com.tom.springnote.chapter06.autowiredqualifierannotation.RoomDAO" />
    <bean id="hotelDAO" class="com.tom.springnote.chapter06.autowiredqualifierannotation.HotelDAO" />
    <bean id="hotelDAO2" class="com.tom.springnote.chapter06.autowiredqualifierannotation.HotelDAO" />

</beans>

【补充】 如果xml文件中只注入 AutowiredAnnotationBeanPostProcessor , 而不引入 <context:annotation-config />元素, 则无法激活 @Qualifier注解。 这会导致spring自动绑定依赖关系时,若发现同一个类有多个bean,则抛出异常 【No qualifying bean of type ‘XXX’ available: expected single matching bean but found 2: XXX1, XXX2】。


【2.4】JSR250注解

1) jsr250,即第250号java规范请求,其提供的注解包括 @Resource, @PostConstruct , @PreDestory ;

  • @Resource: 根据byName自动绑定依赖注入关系; 可以标注属性和方法,但不能标注构造器;
  • @PostConstruct: bean实例化后被调用(构造器执行后被调用)
  • @PreDestory: bean销毁前被调用

【2.4.1】 @Resource注解标注依赖注入关系代码

【Jsr250AnnotationAutowireMain】JSR250注解自动装配main入口

public class Jsr250AnnotationAutowireMain {
    public static void main(String[] args) {
        String[] locations = {"classpath:chapter06/beans0601autowirequlifierannotation.xml"
                , "classpath:chapter06/beans0601jsr250annotation.xml"};
        ClassPathXmlApplicationContext container = new ClassPathXmlApplicationContext(locations);
        // 若有bean销毁前执行回调,则需要注册关闭钩子回调
        container.registerShutdownHook();
        container.getBean(Jsr250AnnotationBookAppService.class).book("JSR250#@Resource注解的自动绑定01", "张三");
        System.out.println("容器关闭");
    }
}

【Jsr250AnnotationBookAppService】JSR250注解@Resource标注bean以便自动绑定依赖关系

public class Jsr250AnnotationBookAppService {

    @Resource(name = "bookDomainService2")
    private AutowireQualifierBookDomainService annotationBookDomainService;

    public Jsr250AnnotationBookAppService() {
        System.out.println("Jsr250AnnotationBookAppService 构造器");
    }

    public void book(String roomId, String customer) {
        annotationBookDomainService.book(roomId, customer);
    }

    @PostConstruct
    public void afterInstance() {
        System.out.println("@PostConstruct注解标注的方法,实例化之后执行");
    }

    @PreDestroy
    public void destory() {
        System.out.println("@PreDestroy注解标注的方法,bean销毁前执行");
    }
}

【打印日志】

Jsr250AnnotationBookAppService 构造器
@PostConstruct注解标注的方法,实例化之后执行
希尔顿酒店预订助手
HotelDAO#IfAuthLegal(): [张三]权限校验合法
权限校验成功
RoomDAO#insertRoomBook(): 插入订房信息成功:roomId=[JSR250#@Resource注解的自动绑定01], customer=[张三]
容器关闭
@PreDestroy注解标注的方法,bean销毁前执行

@Resource注解作用总结

@Resource注解可以替代 @Autowired 与 @Qualilfier这2个注解结合的功能,即根据beanName到spring容器中查找匹配的bean,并注入依赖关系到当前bean(如Jsr250AnnotationBookAppService);
在这里插入图片描述

【2.4.2】@PostConstruct 与 @PreDestroy注解

1) @PostConstruct: bean实例化后被调用(构造器执行后被调用);

  • 总结:bean实例化后的生命周期管理方式:
    • @PostConstruct注解;
    • 实现 InitializingBean接口;
    • 通过 init-method 指定初始化方法;

2)@PreDestroy: bean销毁前被调用;

  • 总结:bean销毁前执行回调的生命周期管理方式:
    • @PreDestroy注解;
    • 实现 DisposableBean 接口;
    • 通过 destory-method 指定销毁前的回调方法;

补充: 代码示例参见 Jsr250AnnotationBookAppService ;


【2.5】 <context:component-scan>开启spring组件扫描

1)背景: 2.2 与 2.3的代码示例中, xml配置文件仅注册bean,不管理bean的依赖关系; 其依赖关系通过注解来管理; 即需要编写xml配置与注解;当bean比较多的时候,开发xml配置文件比较繁琐;

2)解决方法: 使用 classpath-scanning 扫描给定路径的package;

  • 当扫描到某个类标注对应注解后,就提取该类的相关信息,构建对应 BeanDefinition,并把BeanDefinition注册到容器。
  • 接着容器遍历BeanDefinition实例化bean,并通过标注注解的对应BeanPostProcessor来注入依赖关系;

3)classpath-scanning组件扫描功能,通过在xml文件配置 <context:component-scan> 来开启;

  • <context:component-scan> 默认扫描 @Component注解标注的类,并实例化bean;
  • 此外, 因为 @Controller注解, @Service注解, @Repository注解 是基于@Component定义的,所以上述3个也可以被 <context:component-scan> 扫描到

4)补充: <context:component-scan> 元素,可以新增属性 include-filter 和 exclude-filter 分别包含和排除某些package ;


【2.5.1】开启组件扫描的自动绑定代码示例

【ComponentScanMain】main入口

public class ComponentScanMain {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext container = new ClassPathXmlApplicationContext("classpath:chapter06/beans0601componentscan.xml");
        container.getBean(ComponentScanAppService.class).scan();
    }
}

【beans0601componentscan.xml】 配置了 <context:annotation-config/> 元素, <context: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.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 注册5个BeanPostProcessor,间接激活多个自动绑定注解及JSR250注解,包括 @Autowired, @Qualiifer, @Resource, @PostConstruct, @PreDestory  -->
    <context:annotation-config/>
    <!-- 开启组件扫描,无需手工在xml配置文件注册每个bean -->
    <context:component-scan base-package="com.tom.springnote.chapter06.componentscan,com.tom.springnote.chapter06.componentscan2" />

</beans>

【ComponentScanAppService】 ( 使用 @Service注解

@Service
public class ComponentScanAppService {

    @Autowired
    private ComponentScanDomainService scanComponentDomainService;

    public void scan() {
        scanComponentDomainService.scan();
    }
}

【ComponentScanDomainService】( 使用 @Service注解

@Service
public class ComponentScanDomainService {
    @Autowired
    @Qualifier("hiltonComponenetScanSupportImpl")
    private IComponentScanSupport componentScanSupport;

    public void scan() {
        componentScanSupport.scan();
    }
}

【IComponentScanSupport】

public interface IComponentScanSupport {

    void scan();
}

【HiltonComponenetScanSupportImpl】 ( 使用 @Component注解

@Component("hiltonComponenetScanSupportImpl")
public class HiltonComponenetScanSupportImpl implements IComponentScanSupport {

    @Autowired
    private ComponentScanDAO scanComponentDAO;

    @Override
    public void scan() {
        System.out.println("希尔顿组件扫描助手");
        scanComponentDAO.scan();
    }
}

【WandaComponenetScanSupportImpl】 ( 使用 @Component注解

@Component("wandaComponenetScanSupportImpl")
public class WandaComponenetScanSupportImpl implements IComponentScanSupport {

    @Autowired
    private ComponentScanDAO scanComponentDAO;

    @Override
    public void scan() {
        System.out.println("万达组件扫描助手");
        scanComponentDAO.scan();
    }
}

【ComponentScanDAO】 ( 使用 @Repository注解

@Repository
public class ComponentScanDAO {
    public void scan() {
        System.out.println("ScanComponentDAO#scan():扫描完成");
    }
}

【打印日志】

希尔顿组件扫描助手
ScanComponentDAO#scan():扫描完成

【3】小结

1)本文描述了2种自动绑定依赖关系的方式, 包括xml配置文件版本的自动绑定,注解版本的自动绑定;

  • 依赖注入自动化: 在介绍注解版本的自动绑定时,本文引入了 <context:annotation-config> xml元素 ,它注册5个BeanPostProcessor,间接激活多个自动绑定注解及JSR250注解,包括 @Autowired, @Qualiifer, @Resource, @PostConstruct, @PreDestory ; 有了这些组件,我们可以实现自动绑定依赖关系,而无需手工在xml文件中配置每个bean的依赖关系, 开发量显著减少;
  • 对象bean注册自动化:本文还引入了 <context:component-scan> xml元素, 开启组件扫描,无需手工在xml配置文件注册每个bean ;

2)问题:能否仅使用注解实现自动绑定; 答案是否;

  • 因为无法通过注解来标注第三方提供的类库;即针对第三方类库, 我们可以结合使用基于配置文件的依赖注入方式;因为基于xml的依赖注入方式是spring提供的最基本,最强大的表达方式

【补充】 JSR250

1)JSR,Java Specification Request, 即 java规范请求: 是 Java 平台提议和最终规范的实际描述。任何时候都有大量 JSR 正在通过审查和批准流程。 JSR250表示第250号java规范请求; 参见 https://jcp.org/en/jsr/overview ;JSR清单,参见:https://jcp.org/en/jsr/all

简单理解, 开发者自行开发了api,把api封装到JSR并报送给java社区;审批通过后,以JSR形式发布api;



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2049626.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面向财商人群的AI垂直产品 —— AI股票助手

在数字化转型的大潮中,AI技术正在重塑各行各业,尤其是金融市场。对于那些渴望在瞬息万变的股市中保持敏锐洞察力的金融分析师、投资者及股票爱好者来说,一款强大而智能的工具显得尤为重要。今天,我们将向大家介绍一款专为财商人群打造的AI垂直产品——AI股票助手。 一、产…

mac如何恢复被同名替换掉的文件夹 mac文件被替换如何恢复

Mac系统一直以高性能遥遥领先其他的Windows系统&#xff0c;因此&#xff0c;Mac虽然价格远远高出其他的笔记本电脑&#xff0c;但是还是受到了一众用户的青睐。使用mac时&#xff0c;我们也经常会将一个文件命名为已经有了相同文件的文件名&#xff0c;且保存到同一个目标地址…

吴恩达机器学习-C2W3-多类分类

目标 在本实验中&#xff0c;您将探索一个使用神经网络进行多类分类的示例。 工具 您将使用一些绘图例程。它们存储在这个目录下的lab_utils_multiclass_TF.py中。 import numpy as np import matplotlib.pyplot as plt %matplotlib widget from sklearn.datasets import …

centos7.9最小化安装之后的配置与下载

一. 配置yum源 1.备份系统自带源文件 cd /etc/yum.repos.d/ mkdir bak mv *.repo bak 2. 配置阿里云yum源 若有wget wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo若没有wget&#xff0c;先直接把 http://mirrors.aliyun.com/re…

11.怎么做好一个动态标签页

效果 步骤 1.在Elementui找一个标签页组件 复制粘贴到代码 2.将他写活 将很多页面需要用的方法和变量写入store editableTabsValue: 2,editableTabs: [{title: 首页,name: index,},],addTab(state, tab) {if (state.editableTabs.findIndex(item > item.title tab.titl…

mysql5.7主从同步失败原因总结-windows

1&#xff0c;主库data文件复制到从库&#xff0c;之后主库要同步的实例data一定不要在修改&#xff1b; 1.1&#xff0c;修改之后就要重新覆盖一遍修改过的data 2&#xff0c;如果状态不对&#xff1a;一定要查看日志&#xff1b;比如slave_io_state是空时&#xff0c;需要查…

KEEPALIVED 全csdn最详细----理论+实验(干货扎实,包教会的)

环境准备 主机名IP虚拟IP&#xff08;VIP&#xff09;功能ka1172.25.254.10172.25.254.100keepalived服务ka2172.25.254.20172.25.254.100keepalived服务realserver1172.25.254.110web服务realserver2172.25.254.120web服务 注意一定要关闭selinux,和防火墙&#xff0c;不然在…

zabbix7.0 设置中文语言( Debian GNU/Linux 12)

本例为安装zabbix7.0 zabbix_server (Zabbix) 6.4.17 Revision c12261f00b4 15 July 2024, compilation time: Jul 15 2024 11:05:06 系统版本信息为 lsb_release -a No LSB modules are available. Distributor ID: Debian Description: Debian GNU/Linux 12 (bookworm) Rele…

防疫物资管理信息系统pf

TOC springboot379防疫物资管理信息系统pf 第1章 绪论 1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电脑和笔记本的广泛…

【Django开发】前后端分离django美多商城项目第2篇:展示用户注册页面,1. 创建用户模块子应用【附代码文档】

全套笔记资料代码移步&#xff1a; 前往gitee仓库查看 感兴趣的小伙伴可以自取哦~ 本教程的知识点为&#xff1a; 项目准备 项目准备 配置 1. 修改settings/dev.py 文件中的路径信息 2. INSTALLED_APPS 3. 数据库 用户部分 图片 1. 后端接口设计&#xff1a; 视图原型 2. 具体…

【网络安全】SSO登录过程实现账户接管

未经许可,不得转载。 文章目录 正文正文 登录页面展示了“使用 SSO 登录”功能: 经分析,单点登录(SSO)系统的身份验证过程如下: 1、启动SSO流程:当用户点击按钮时,浏览器会发送一个GET请求到指定的URL: /idp/auth/mid-oidc?req=[UNIQUE_ID]&redirect_uri=[REDI…

在 Mac 上更改 24小时制时间显示

使用“日期与时间”设置设定或更改 Mac 上的日期和时间。如果日期和时间正确&#xff0c;那么电子邮件、信息和文件上的时间戳也是准确的。了解如何设定日期和时间。 若要更改这些设置&#xff0c;请选取苹果菜单 >“系统设置”&#xff0c;点按边栏中的“通用” &#x…

[星瞳科技]OpenMV使用时有哪些常见错误和解决办法?

常见代码错误 ImportError:no module named xxx 这个错误是Import错误&#xff0c;没有stepper这个模块。 原因&#xff1a; 你没有把stepper.py这个文件拖到你的板子里。见&#xff1a;模块的使用 拖过去之后&#xff0c;需要重启&#xff0c;使模块生效 MemoryError:FB …

Class字节码文件结构

class字节码文件结构 类型名称说明长度数量u4magic魔数,识别Class文件格式4个字节1u2minor_version副版本号(小版本)2个字节1u2major_version主版本号(大版本)2个字节1u2constant_pool_count常量池计数器2个字节1cp_infoconstant_pool常量池表n个字节constant_pool_count-1u2a…

马头拧紧驱动器维修 拧紧控制器故障

马头拧紧控制器作为工业自动化领域不可或缺的重要设备&#xff0c;其稳定运行对于生产线的效率与安全性至关重要。然而&#xff0c;在实际应用中&#xff0c;难免会遇到各种Desoutter拧紧工具控制器故障&#xff0c;影响生产进度和设备性能。 拧紧轴控制器维修 拧紧装置 马头…

ubuntu设置共享文件夹,非虚拟机,服务器版

在Ubuntu中共享文件夹通常可以通过几种不同的方式来实现&#xff0c;比如使用Samba服务、NFS&#xff08;Network File System&#xff09;或者通过虚拟机软件如VirtualBox或VMware的内置共享文件夹功能。这里我假设您是在询问如何在Ubuntu主机上设置一个简单的文件共享服务&am…

MongoDB Redis 快速上手:NoSQL数据库操作精要

先言之 ☘️随着大数据时代的到来&#xff0c;非关系型数据库因其灵活性和扩展性逐渐受到开发者的青睐。MongoDB 和 Redis 作为两种非常流行的 NoSQL 数据库&#xff0c;各自拥有独特的特性和应用场景。MongoDB 是一款面向文档的数据库&#xff0c;适用于需要存储复杂数据结构…

ESP32-C3在MQTT访问时出现“transport_base: Poll timeout or error”问题的分析(2)

接前一篇文章:ESP32-C3在MQTT访问时出现“transport_base: Poll timeout or error”问题的分析(1) 前一篇文章在分析定位笔者所遇MQTT(MQTTs)传输时问题的时候,定位到了问题是出自于components\components\tcp_transport\transport_ssl.c的ssl_write函数。本回开始,就围…

【四】阿伟开始学Kafka

阿伟开始学Kafka 概述 人生若只如初见&#xff0c;阿伟心里回想起了第一次和Kafka见面的场景&#xff0c;记忆虽然已经有些模糊&#xff0c;但是感觉初次见面是美好的。积累了一些实战经验之后&#xff0c;阿伟感觉不能再是面对百度开发了&#xff0c;于是决心系统的学习一下Ka…

liblzma库Android平台编译

1.下载源码: git clone https://github.com/tukaani-project/xz.git --recursive 2.配置交叉编译环境: 生成Android平台makefile export ANDROID_API=25 export ANDROID_NDK=/opt/aarch64-darwin-android export ANDROID_NDK_REVISION=r25b export AR=/opt/aarch64-darwin-a…