当前位置: 首页 > news >正文

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

文章目录

  • 【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;@Overridepublic 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;@Autowiredpublic RoomBookAppService(RoomBookDomainService bookDomainService) {this.bookDomainService = bookDomainService;}public void book(String roomId, String customer) {bookDomainService.book(roomId, customer);}
}

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

public class RoomBookDomainService {@Autowiredprivate 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;@Overridepublic void saveRoomBookInf(String roomId, String customer) {if (!hotelDAO.IfAuthLegal(customer)) {System.out.println("权限校验失败");return;}System.out.println("权限校验成功");bookDAO.insertRoomBook(roomId, customer);}@Autowiredpublic void setBookDAO(RoomDAO bookDAO) {this.bookDAO = bookDAO;}@Autowiredpublic 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.xsdhttp://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;@Autowiredpublic 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;@Overridepublic void saveRoomBookInf(String roomId, String customer) {System.out.println("希尔顿酒店预订助手");if (!hotelDAO.IfAuthLegal(customer)) {System.out.println("权限校验失败");return;} System.out.println("权限校验成功");bookDAO.insertRoomBook(roomId, customer);}@Autowiredpublic void setBookDAO(@Qualifier("roomDAO") RoomDAO bookDAO) {this.bookDAO = bookDAO;}@Autowiredpublic void injectHotelDAO(@Qualifier("hotelDAO") HotelDAO hotelDAO) {this.hotelDAO = hotelDAO;}
}

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

public class WandaRoomBookSupportImpl implements IAutowireQualifierBookSupport {private RoomDAO bookDAO;private HotelDAO hotelDAO;@Overridepublic void saveRoomBookInf(String roomId, String customer) {System.out.println("万达酒店预订助手");if (!hotelDAO.IfAuthLegal(customer)) {System.out.println("权限校验失败");return;}System.out.println("权限校验成功");bookDAO.insertRoomBook(roomId, customer);}@Autowiredpublic void setBookDAO(@Qualifier("roomDAO2") RoomDAO bookDAO) {this.bookDAO = bookDAO;}@Autowiredpublic 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 {@Overridepublic 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 {@Overridepublic 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 {@Autowiredprivate FileReader fileReader;@Testpublic 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.xsdhttp://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);}@PostConstructpublic void afterInstance() {System.out.println("@PostConstruct注解标注的方法,实例化之后执行");}@PreDestroypublic 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.xsdhttp://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 {@Autowiredprivate 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 {@Autowiredprivate ComponentScanDAO scanComponentDAO;@Overridepublic void scan() {System.out.println("希尔顿组件扫描助手");scanComponentDAO.scan();}
}

【WandaComponenetScanSupportImpl】 ( 使用 @Component注解

@Component("wandaComponenetScanSupportImpl")
public class WandaComponenetScanSupportImpl implements IComponentScanSupport {@Autowiredprivate ComponentScanDAO scanComponentDAO;@Overridepublic 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;



相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 「Unity3D」属性面板(Inspector)上增删操作,序列化的Dictionary对象的k-v数值
  • 【C语言篇】深入理解指针4(模拟实现qsort函数)
  • DIGITEL1500Ion Pump System离子泵系统控制器说明含电路图电路板图
  • 理解和控制 OBS 媒体源 - 前提条件与操作
  • C++ //练习 17.2 定义一个tuple,保存一个string、一个vector<string>和一个pair<string, int>。
  • ECMAScript6中的模块:export导出、import导入
  • MFC将类A中的事件在类B中处理采用回调函数实现
  • MySQL中的distinct和group by哪个效率更高?
  • vba代码插入折线图
  • SQL进阶技巧:如何不使用union all进行行转列?【三种方法实现】
  • 【机器学习】深度学习实践
  • tea-入土为安的第十七天
  • 基于三帧差算法的运动目标检测系统FPGA实现,包含testbench和MATLAB辅助验证程序
  • [C++][opencv]基于opencv实现photoshop算法图像剪切
  • Java的jdk配置成功,但是输入java -version等,命令行没有任何反应
  • 【译】JS基础算法脚本:字符串结尾
  • 「译」Node.js Streams 基础
  • 【mysql】环境安装、服务启动、密码设置
  • Electron入门介绍
  • IDEA 插件开发入门教程
  • Java超时控制的实现
  • Leetcode 27 Remove Element
  • underscore源码剖析之整体架构
  • Web设计流程优化:网页效果图设计新思路
  • 初识 beanstalkd
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 使用 QuickBI 搭建酷炫可视化分析
  • 网络应用优化——时延与带宽
  • 小程序01:wepy框架整合iview webapp UI
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • nb
  • Semaphore
  • # 计算机视觉入门
  • #控制台大学课堂点名问题_课堂随机点名
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (纯JS)图片裁剪
  • (二)斐波那契Fabonacci函数
  • (四)linux文件内容查看
  • (四)React组件、useState、组件样式
  • (转)GCC在C语言中内嵌汇编 asm __volatile__
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • .DFS.
  • .NET 8 跨平台高性能边缘采集网关
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET Core 发展历程和版本迭代
  • .net 程序发生了一个不可捕获的异常
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • .net的socket示例
  • .net生成的类,跨工程调用显示注释
  • .NET文档生成工具ADB使用图文教程
  • .NET性能优化(文摘)
  • .NET中的十进制浮点类型,徐汇区网站设计
  • @RequestBody与@RequestParam
  • [<事务专题>]
  • [000-01-030].Zookeeper学习大纲