第一章、注解基础概念

1. 什么是注解编程

指的是在类或者方法上加入特定的注解(@XXX),完成特定功能的开发

  • 特定的注解 —> 特定的功能

示例:

  1. @Component
  2. public class XXX{
  3. }

2. 为什么要讲解注解编程

  1. 注解开发方便
  • 代码简洁 开发速度大大提高
  1. Spring开发潮流
  • Spring2.x 引入注解
  • Spring3.x 完善注解
  • SpringBoot 推广注解编程

    3. 注解的作用

    3.1 简化配置

    替换XML这种配置形式
    image.png

    3.2 接替接口的契约性

    替换接口,实现调用双方的契约性

    3.2.1 接口实现契约性

  • 过往中,如果调用者和功能的开发者是两拨人,那么他们之间的开发规范(契约性)一般就是通过接口来实现

    • 调用的方法名称
    • 调用的方法的入参出参
  • 比如,tomcat 的 Servlet 接口,调用者(Tomcat 服务器)对于来到服务器的请求,需要调用功能来处理请求,而这个调用的功能需要符合 tomcat 的规范,因此 tomcat 就设计了 Servlet 接口,所有实现了 Servlet 接口的实现类,都能被 tomcat 调用来处理请求
  • image.png

    3.2.2 接口实现契约性的缺点

  • 实现类需要完全实现接口的所有方法,如 Servlet 接口,很多时候只需要写 service 方法,却不得不写其他的四个方法(init、destory、等等)

    • 解决方法:使用适配器,如:Servlet 有一个 HttpServlet 的实现类,其实现了这5个方法,我们只需要继承 HttpServlet,然后覆写 service 方法就行。但这样不够优雅,比较繁琐

      3.2.3 注解实现契约性

  • 调用双方约定一个注解,调用者直接通过反射遍历功能提供者的各个方法,找到贴有这个注解的方法,通过反射调用

  • 比如:Spring 框架中的 aop 功能
    • 如果通过接口的方式来实现,则功能的提供者需要作为 MethodInterceptor 接口的实现类,实现 invoke() 方法
    • 如果通过注解来实现,则功能的提供者只需要在功能的实现方法上贴上 @Around 注解即可

image.png
通过注解的方式,在功能调用者和功能提供者之间达成约定,进而进行功能的调用。
因为注解应用更为方便灵活,所以在现在的开发中,更推荐通过注解的形式完成

4. Spring 注解的发展历程

  1. Spring2.x开始支持注解编程 @Component @Service @Scope … ….
  • 目的:提供的这些注解只是为了在某些情况下简化XML的配置,作为XML开发的有益补充
  • 依旧是需要使用 XML 的
  1. Spring3.x @Configuration @Bean … …
  • 目的:彻底替换XML,基于纯注解编程
  1. Spring4.x、Spring5、SpringBoot
  • 提倡使用注解常见开发

    5. Spring注解开发耦合问题

    Spring基于注解进行配置后,配置信息就与代码耦合在一起了
    当对于注解不满意时,此时可以通过Spring配置文件进行覆盖,覆盖掉注解的内容,也即解耦
    Spring 配置信息的优先级

  • 注解 < **@Configuration** 配置Bean < xml配置文件

    第二章、Spring的基础注解(Spring2.x)

    这个阶段的注解,仅仅是简化XML的配置,并不能完全替代XML

搭建开发环境

  • 设置 Spring Context 的扫描范围
  • <context:component-scan base-package="com.baizhiedu"/>

作用:让Spring框架在设置包及其子包中扫描对应的注解,使其生效。

1. 对象创建相关注解

1.1 @Component

image.png

  • 作用:替换原有spring配置文件中的<bean标签
  • 注意:

    • id属性 component注解提供了默认的设置方式:首单词首字母小写
    • class属性 通过反射获得 class 内容,也即类的全限定类名

      1.2 @Component 细节

  • @Component("u"):显示指定工厂创建对象的id值

  • Spring配置文件覆盖注解配置内容

    • applicationContext.xml 中:<bean id="u" class="com.baizhiedu.bean.User"/>
    • 注意:id值 class的值 要和注解中的设置保持一值,如果不一致,Spring 就会生成一个新的 bean 对象

      1.3 @Component 的衍生注解

  • 这些衍生注解本质上就是 **@Component**使用和作用和其一模一样,等同于 bean 标签

  • 使用衍生注解的目的是为了更加准确的表达一个类型的作用
    • 如,在 Service 层使用 @Component 是完全可以的,但更建议使用 @Service ,表明这个是 Service 层的 bean

image.png

  • @Repository:用于表明这是 DAO 层的 bean ```java @Repository public class UserDAO{

}

  1. - `@Service`:用于表明这是 Service 层的 bean
  2. ```java
  3. @Service
  4. public class UserService{
  5. }
  • @Controller:用于表明这是 Controller 层的 bean ```java @Controller public class RegAction{

}

  1. <a name="rrpXr"></a>
  2. ### 1.4 bean标签属性注解
  3. `@Scope` 注解
  4. - 作用:控制简单对象创建次数 `<bean id="" class="" scope="singleton|prototype"/>`
  5. - 注意:不添加 `@Scope` Spring提供默认值 **singleton**
  6. ```java
  7. @Component
  8. @Scope("prototype")
  9. public class User{
  10. }

@Lazy 注解

  • 作用:延迟创建单实例对象 <bean id="" class="" lazy="false"/>
  • 注意:一旦使用了 @Lazy 注解后,Spring会在使用这个对象时候,才进行这个对象的创建

    1.5 bean 生命周期方法相关注解

    @PostConstruct:初始化方法,在对象注入后使用

  • <bean init-method=""/>

  • 使用场景:MQ 配置的初始化可以使用这个
  • 执行顺序
    • Constructor >> Autowired >> PostConstruct

@PreDestroy:销毁方法,在销毁对象之前使用

  • <bean destory-method=""/>

image.png
注意

  • 上述的2个注解并不是Spring提供的,为 JSR(JavaEE规范)520 的内容,但Spring很好地支持了,所以可以在Spring框架中使用这个
  • 再一次的验证,通过注解实现了接口的契约性
    • 以往如果不想在 xml 中配置 bean 的初始化、销毁方法,就需要在 bean 的类中实现两个接口 InitializingBeanDisposableBean,并实现这两个接口的方法
    • 现在通过直接给bean 类中的两个方法贴上注解,就可以直接表明那个是 bean 的初始化方法,哪个是 bean 的销毁方法
    • 比使用接口更加灵活方便

      2. 注入相关注解

      2.1 用户自定义类型注入:@Autowired

      2.1.1 xml 配置方式注入用户自定义类型

  1. 有一个 Service bean 类,其有一个自定义类型属性 userDAO
  2. 在 xml 中配置 service 和 dao 的 <bean 标签,让 Spring 管理
  3. service 的 <bean 标签下,使用 <property 标签将 dao 的bean 作为属性注入给 service 的bean
    • <property 这里是借用的 service 类中属性的 setter 方法进行注入的,本质是通过反射获得 setter 方法将值写入

image.png

2.1.2 @Autowired 的基本使用

  1. 有一个 Service bean 类,其有一个自定义类型属性 dao
  2. Service 类中加上 @Service 注解,Dao 类中加上 @Repository 注解,让他们分别交由 Spring 容器管理
  3. @Service 类中的 userDAO 属性的 setter 方法贴上 @Autowried 注解,完成对 dao bean 的注入

image.png

2.1.3 @Autowired 细节

  1. 注入的方式(类型注入与 beanId 注入)
    1. @Autowired 默认是基于类型进行注入
      • 基于类型的注入:注入对象的类型,必须与目标成员变量类型相同或者是其子类实现类
      • 例如:Service 有个 UserDao 的属性,则只有实现了 UserDao 接口的实现类,如 UserDaoImpl 才能被注入这个属性
    2. @Autowired@Qualifier 配合使用,可以实现 基于beanID 进行注入
      • 基于名字的注入:注入对象的id值,必须与 @Qualifier 注解中设置的名字相同
      • 使用场景:对于有多个实现类,且多个实现类都放到了 Spring Context 中
      • 如:不同集群的ES操作类,可以通过 @Qualifier 的方式,在不同的地方指定注入不同的实现类
    • image.png
  2. @Autowired 注解放置位置
    1. 放置在对应成员变量的set方法上
    2. 直接把这个注解放置在成员变量之上Spring通过反射直接对成员变量进行注入(赋值),而不通过 setter 方法
      • 同样的,@Qualifier 也可以放到成员变量上
  3. @Resouce
  • 是 JavaEE 规范 JSR250 中类似注入功能的注解,Spring 对其进行了支持
  • 基于名字进行注入:@Resouce(name="userDAOImpl")
    • 实际效果就相当于:@Autowired() + @Qualifier("userDAOImpl")
  • 基于类型进行注入:@Resouce,也即不加 name
  • 注意:如果在应用 @Resouce 注解时,名字没有配对成功,那么他会继续按照类型进行注入。
  1. @Inject
  • 是 JavaEE 规范 JSR330 中的注解,作用 @Autowired 完全一致 基于类型进行注入,需要额外导入依赖使用,基本已经废弃
    1. <dependency>
    2. <groupId>javax.inject</groupId>
    3. <artifactId>javax.inject</artifactId>
    4. <version>1</version>
    5. </dependency>

    2.2 JDK类型注入:@Value

    2.2.1 注入步骤

  1. 设置 xxx.properties 属性配置文件,里面写上键值对

    1. id = 10
    2. name = suns
  2. Spring的工厂读取这个配置文件,也即在Spring 的配置文件中,指定Spring去读取这个 properties 文件

  • <context:property-placeholder location=""/>
  1. 在需要注入的 bean 的属性上,贴上 @Value("${key}") 注解,Spring 就会将 properties 文件对应 key 的 value 注入到这个属性上

image.png

  • 问题:依旧需要在 xml 文件中使用标签指定 properties 文件的路径

    2.2.2 @Value 注解使用细节

  • @Value 注解不能应用在静态(static)成员变量上,否则赋值(注入)失败

  • @Value +Properties 配置文件的方式,不能注入集合类型,需要通过Spring提供新的配置形式 YAML YML (SpringBoot)

    2.2.3 properties 配置文件位置

    @PropertySource:指定 xxx.properties 配置文件所在位置

  • 作用:用于替换Spring配置文件中的 <context:property-placeholder location=""/> 标签

  • 配合 @Value 一起使用
  • 开发步骤
    1. 设置 xxx.properties,写键值对
    2. 应用 @PropertySource
    3. 代码

image.png

3. 注解扫描详解

3.1 使用 xml 的方式

  • <context:component-scan base-package="com.baizhiedu"/>
  • 标识扫描当前包及其子包

    3.1.1 排除包扫描的方式

    使用示例

    1. <context:component-scan base-package="com.baizhiedu">
    2. <context:exclude-filter type="" expression=""/>
    3. </context:component-scan>

    排除策略的解析

  • assignable:排除特定的类型 不进行扫描,例如:com.haniel.bean.User 就是类型为 User 的类都不扫描

  • annotation:排除特定的注解 不进行扫描,例如:org.springframework.stereotype.Service 就是所有贴 @Service 注解的类不扫描
  • aspectj:切入点表达式,实际中使用这个最多
    • 包切入点: com.baizhiedu.bean..*
    • 类切入点: *..User
  • regex:正则表达式
  • custom:自定义排除策略,用于框架底层开发

image.png
应用场景

  • 当写自己的框架应用到Spring时,需要考虑有些类不需要Spring帮忙创建并管理,此时就需要将这些类排除出去

排除策略可以叠加使用

  1. <context:component-scan base-package="com.baizhiedu">
  2. <context:exclude-filter type="assignable" expression="com.baizhiedu.bean.User"/>
  3. <context:exclude-filter type="aspectj" expression="com.baizhiedu.injection..*"/>
  4. </context:component-scan>

3.1.2 包含方式

如果需要排除的太多,则排除规则设置过于复杂,此时就可以反其道而行之,设置包含的规则
使用示例

  1. 让Spring默认的注解扫描方式失效 **use-default-filters="false"**
    • 默认策略就是扫描 base-package 设置的包及其子包
  2. 指定扫描那些注解 <context:include-filter type="" expression=""/>
    1. <context:component-scan base-package="com.baizhiedu" use-default-filters="false">
    2. <context:include-filter type="" expression=""/>
    3. </context:component-scan>
    扫描策略的解析
  • assignable:指定特定的类型,进行扫描
  • annotation:指定特定的注解,进行扫描
  • aspectj:切入点表达式
    • 包切入点:com.baizhiedu.bean..*
    • 类切入点:*..User
  • regex:正则表达式
  • custom:自定义排除策略,一般用于框架底层开发

包含的方式支持叠加

  1. <context:component-scan base-package="com.baizhiedu" use-default-filters="false">
  2. <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
  3. <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
  4. </context:component-scan>

4. 对于注解开发注意

4.1 配置互通

Spring注解配置和配置文件的配置是互通的,也即通过注解配置的bean,可以直接在配置文件中注入到别的bean 的属性中
注解方式配置bean

  1. @Repository
  2. public class UserDAOImpl{
  3. }

配置文件中使用这个bean

  • 因为注解方式已经让 Spring 管理了UserDAOImpl类,其beanId默认为类名 userDAOImpl,注解和配置文件两种方式互动,因此配置文件配置时,可以直接拿注解配置的bean进行注入

    1. <bean id="userService" class="com.baizhiedu.UserServiceImpl">
    2. <property name="userDAO" ref="userDAOImpl"/>
    3. </bean>

    4.2 Spring2.x 可以使用注解的情况

    自己开发的可以使用注解

  • @Component 及其衍生注解、@Autowired @Value 等等这些注解,都有一个共同特点:用于我们自己开发的类,如:User UserService UserDAO UserAction 等,自己可以加上这些注解来控制类是否交由Spring管理,如何注入等

第三方的无法使用注解,需要使用xml配置文件

  • 但是对于第三方的类,如 SqlSessionFactoryBean、MapperScannerConfigure 等,这些原生并不支持Spring的注解,自然没法无中生有出现这些注解,依旧需要使用 <bean 进行配置的

后面这种情况可以使用配置Bean(@Configuration + @Bean) 替代 xml 配置文件+

第三章、Spring的高级注解(Spring3.x 及以上)

1. 配置Bean

1.1 作用

  • Spring3.x 提供了新的注解,用于替换XML配置文件

    1.2 简单示例

    ```java @Configuration public class AppConfig{

}

  1. <a name="mpBRg"></a>
  2. ### 1.3 配置Bean取代了xml配置文件的作用
  3. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1636900267277-2863aa9a-5fed-4e71-8535-652480ae6ee9.png#clientId=u303fba85-ca5e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=438&id=uf3e70b09&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1063&originWidth=2230&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1691274&status=done&style=none&taskId=ucf42558d-f70d-4b8a-94d3-529ae443874&title=&width=918)
  4. <a name="MucQ8"></a>
  5. ### 1.4 使用的 ApplicationContext 实现类为 `AnnotationConfigApplicationContext`
  6. - 使用 xml 配置文件时,使用的 ApplicationContext 实现类为 ClassPathXmlApplicationContext,需要传 xml 配置文件的路径
  7. - 现在使用配置Bean取代xml配置文件后,使用的 ApplicationContext 实现类为 AnnotationConfigApplicationContext,传配置Bean的class类
  8. - 也可以传指定配置bean所在的路径 `ApplicationContext ctx = new AnnotationConfigApplicationContext("com.baizhiedu");`让Spring自行扫描这个包下包含 `@Configuration` 的配置Bean
  9. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1636900453383-bb5271fd-8145-4783-b3b1-165069c64f6b.png#clientId=u303fba85-ca5e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=256&id=uea58eb84&margin=%5Bobject%20Object%5D&name=image.png&originHeight=677&originWidth=2153&originalType=binary&ratio=1&rotation=0&showTitle=false&size=543509&status=done&style=none&taskId=u45ce1e90-63fc-49b0-b04b-878f4276f44&title=&width=815)
  10. <a name="YbKrh"></a>
  11. ### 1.5 `@Configuration` 注解的本质
  12. - **是 **`**@Component**`** 注解的衍生注解**,**将配置 bean 交由Spring Context 管理**
  13. - 可以应用 <context:component-scan 标签进行扫描,但没有必要,因为 `@Configuration` 就是用来取代 xml 的
  14. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1636900994446-eebe1ec4-4f15-4731-890b-5251c1b162d8.png#clientId=u303fba85-ca5e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=347&id=MvtYa&margin=%5Bobject%20Object%5D&name=image.png&originHeight=693&originWidth=1431&originalType=binary&ratio=1&rotation=0&showTitle=false&size=491738&status=done&style=shadow&taskId=u3195a343-a298-4da4-8590-bfa434e86d5&title=&width=715.5)
  15. <a name="lFwhn"></a>
  16. ### 1.6 配置Bean开发的细节分析
  17. - 基于注解开发使用日志:不能集成 Log4j,使用的是集成 logback
  18. - 引入相关jar
  19. ```xml
  20. <dependency>
  21. <groupId>org.slf4j</groupId>
  22. <artifactId>slf4j-api</artifactId>
  23. <version>1.7.25</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.slf4j</groupId>
  27. <artifactId>jcl-over-slf4j</artifactId>
  28. <version>1.7.25</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>ch.qos.logback</groupId>
  32. <artifactId>logback-classic</artifactId>
  33. <version>1.2.3</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>ch.qos.logback</groupId>
  37. <artifactId>logback-core</artifactId>
  38. <version>1.2.3</version>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.logback-extensions</groupId>
  42. <artifactId>logback-ext-spring</artifactId>
  43. <version>0.1.4</version>
  44. </dependency>
  • 引入logback配置文件 (logback.xml)
    ```xml <?xml version=”1.0” encoding=”UTF-8”?>

    %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

  1. <a name="jt5lQ"></a>
  2. ## 2. @Bean注解
  3. <a name="Z7naA"></a>
  4. ### 1.1 作用
  5. - `@Bean` 注解在**配置bean**中进行使用,**等同于XML配置文件中的<bean标签**
  6. <a name="iUXUK"></a>
  7. ### 1.2 @Bean注解的基本使用
  8. 对象的创建
  9. - 简单对象:直接能够通过new方式创建的对象,如:User、UserService、UserDAO
  10. - 复杂对象:不能通过new的方式直接创建的对象,如:Connection、SqlSessionFactory
  11. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1633759288994-7ade2cdb-af37-456c-b758-109e8b2bcf92.png#clientId=uaeaf26fd-104c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=376&id=u48be2228&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1433&originWidth=2752&originalType=binary&ratio=1&rotation=0&showTitle=false&size=862388&status=done&style=none&taskId=u9ed87821-dfb6-4cd8-810b-c42009371df&title=&width=723)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1636902749931-0fc5054a-839b-4fe4-8bf5-3d7f28654567.png#clientId=u303fba85-ca5e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=469&id=ufb3a9188&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1062&originWidth=2081&originalType=binary&ratio=1&rotation=0&showTitle=false&size=548795&status=done&style=shadow&taskId=uea1edb96-9c20-4b9b-9187-6dbeb0c33dd&title=&width=919)<br />`@Bean` 注解创建复杂对象使用工厂
  12. - 使用工厂的方式创建复杂对象
  13. - **一般使用在遗留系统中**,比如旧的 Spring 项目使用 xml 配置文件,现在要改成使用配置bean的方式
  14. - **如果是新系统的话,直接使用在**`**@Bean**`**的方法中创建复杂对象并配置好后返回即可,不用绕一圈使用工厂的方式**
  15. 1. 工厂类实现 Spring 的 FactoryBean 接口
  16. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1636902883143-1090bd54-3919-4acb-871b-6e6e4f80efc2.png#clientId=u303fba85-ca5e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=339&id=u486e646c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=771&originWidth=2150&originalType=binary&ratio=1&rotation=0&showTitle=false&size=571391&status=done&style=shadow&taskId=u47b90f92-153f-4fe7-9680-6f86d6cf1ee&title=&width=944)
  17. 2. 直接在 `@Bean` 的方法里,直接new工厂的对象,调用 `getObject()` 方法就行了
  18. ```java
  19. @Bean
  20. public Connection conn1() {
  21. Connection conn = null;
  22. try {
  23. ConnectionFactoryBean factoryBean = new ConnectionFactoryBean();
  24. conn = factoryBean.getObject();
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. return conn;
  29. }

自定义id值

  • @Bean("id")

控制对象创建次数

  1. @Bean
  2. @Scope("singleton|prototype") 默认值 singleton

1.3 @Bean注解的注入

1.3.1 用户自定义类型

xml 配置文件的方式
image.png
通用的配置Bean方式

  • 先通过 @Bean 配置好 userDAO,其 beanId 为方法名
  • 再在待注入属性的对象的 @Bean 中调用哦 beanId进行注入就行
    • 注意,要定义形参 ```java @Bean public UserDAO userDAO() { return new UserDAOImpl(); }

@Bean public UserService userService(UserDAO userDAO) { UserServiceImpl userService = new UserServiceImpl(); userService.setUserDAO(userDAO); return userService; }

  1. 配置 Bean 的简化方式
  2. - 不用形参
  3. - 注入时直接调用 `userDAO()` **方法**
  4. ```java
  5. @Bean
  6. public UserDAO userDAO() {
  7. return new UserDAOImpl();
  8. }
  9. @Bean
  10. public UserService userService() {
  11. UserServiceImpl userService = new UserServiceImpl();
  12. userService.setUserDAO(userDAO());
  13. return userService;
  14. }

1.3.2 JDK类型注入(耦合)

  1. @Bean
  2. public Customer customer() {
  3. Customer customer = new Customer();
  4. customer.setId(1);
  5. customer.setName("xiaohei");
  6. return customer;
  7. }

1.3.3 JDK类型注入(解耦)

如果直接在代码中进行 set 方法的调用,会存在耦合的问题
建议使用 properties 的方式来解耦合

  1. @Configuration
  2. @PropertySource("classpath:/init.properties")
  3. public class AppConfig1 {
  4. @Value("${id}")
  5. private Integer id;
  6. @Value("${name}")
  7. private String name;
  8. @Bean
  9. public Customer customer() {
  10. Customer customer = new Customer();
  11. customer.setId(id);
  12. customer.setName(name);
  13. return customer;
  14. }
  15. }

3. @ComponentScan注解

介绍

  • @ComponentScan 注解在配置bean中进行使用,等同于XML配置文件中的 <context:component-scan> 标签

目的

  • 进行相关注解的扫描 (@Component @Value@Autowired)

    3.1 基本使用

    image.png
    1. <context:component-scan base-package=""/>
    ```java @Configuration @ComponentScan(basePackages = “com.baizhiedu.scan”) public class AppConfig2 {

}

  1. <a name="jVDnt"></a>
  2. ### 3.2 排除、包含的使用
  3. <a name="tIjUP"></a>
  4. #### 3.2.1 排除
  5. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1636985641362-132a9235-ca18-4231-852c-129e93f8fd8f.png#clientId=u3bd0718e-d226-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=197&id=udf3687d4&margin=%5Bobject%20Object%5D&name=image.png&originHeight=471&originWidth=2064&originalType=binary&ratio=1&rotation=0&showTitle=false&size=718913&status=done&style=shadow&taskId=u2615f725-86fd-4458-9d99-0ecfd6d7935&title=&width=862)
  6. ```xml
  7. <context:component-scan base-package="com.baizhiedu">
  8. <context:exclude-filter type="assignable" expression="com.baizhiedu.bean.User"/>
  9. </context:component-scan>

排除使用的是excludeFilters属性,其为一个数组,可以支持多个排除策略

  1. @ComponentScan(basePackages = "com.baizhiedu.scan",
  2. excludeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION,value={Service.class}),
  3. @ComponentScan.Filter(type= FilterType.ASPECTJ,pattern = "*..User1")})

排除策略类型

  • 如果为 ANNOTATION、ASSIGNABLE_TYPE、CUSTOM,使用的为 value,如:value = {Service.class}
  • 如果为 ASPECTJ、REGEX,使用的是 pattern,如:pattern = "*..User1"

    1. type = FilterType.ANNOTATION value
    2. .ASSIGNABLE_TYPE value
    3. .ASPECTJ pattern
    4. .REGEX pattern
    5. .CUSTOM value

    3.2.2 包含

    1. <context:component-scan base-package="com.baizhiedu" use-default-filters="false">
    2. <context:include-filter type="" expression=""/>
    3. </context:component-scan>

    包含使用的是includeFilters属性,其为一个数组,可以支持多个包含策略

  • 注意,一定要有 useDefaultFilters = false,让Spring放弃原有的默认包含策略

    1. @ComponentScan(basePackages = "com.baizhiedu.scan",
    2. useDefaultFilters = false,
    3. includeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION,value={Service.class})})

    包含策略类型

    1. type = FilterType.ANNOTATION value
    2. .ASSIGNABLE_TYPE value
    3. .ASPECTJ pattern
    4. .REGEX pattern
    5. .CUSTOM value

    4. Spring工厂创建对象的多种配置方式

    4.1 多种配置方式的应用场景

    自己开发的程序:@Component @Autowried 的方式
    调用别人的框架、包:配置Bean 的方式
    image.png

    4.2 配置优先级

    @Component 及其衍生注解 < @Bean < 配置文件 bean标签
    优先级高的配置 覆盖优先级低配置
    举例:

  • 如果对 @Component 注解导入的bean 不满意,可以使用在配置bean(@Configuration) 中使用 @Bean 进行覆盖

  • 如果对 配置bean(@Configuration)的@Bean导入的bean不满意,可以在xml配置文件中使用 <bean 标签进行覆盖

注意:

  • 配置覆盖:id值保持一致
  • 使用注解是,获取 ApplicationContext 使用的是 AnnotationConfigApplicationContext,传入的是配置bean,并没有地方传xml配置文件的地方
  • 因此,Spring3.x 提供了一个注解,@ImportResource("applicationContext.xml"),贴在配置bean上,这样配置bean就能读取xml配置文件的配置了

image.png

  1. @Component
  2. public class User{
  3. }
  4. @Bean
  5. public User user(){
  6. return new User();
  7. }
  8. <bean id="user" class="xxx.User"/>

4.3 解决基于注解进行配置的耦合问题

  1. @Configuration
  2. //@ImportResource("applicationContext.xml")
  3. public class AppConfig4 {
  4. @Bean
  5. public UserDAO userDAO() {
  6. return new UserDAOImpl();
  7. }
  8. }
  9. @Configuration
  10. @ImportResource("applicationContext.xml")
  11. public class AppConfig5{
  12. }
  13. applicationContext.xml
  14. <bean id="userDAO" class="com.baizhiedu.injection.UserDAOImplNew"/>

5. 整合多个配置信息

5.1 多配置信息整合基础

多个配置信息的作用

  • 大型项目中,配置Bean可能长达几千行,维护性极差
  • 拆分多个配置bean的开发,是一种模块化开发的形式,也体现了面向对象各司其职的设计思想
  • 如:不同功能的Bean划分到相同的配置Bean中

image.png
多配置信息整合的方式

  • 第一种:多个配置Bean整合在一起
  • 第二种:配置Bean与@Component相关注解的整合
  • 第三种:配置Bean与SpringXML配置文件的整合:作用:1. 配置信息覆盖;2.遗留系统的整合

整合多种配置需要关注的要点

  • 如何使多配置的信息汇总成一个整体
  • 如何实现跨配置的注入

    5.2 多个配置Bean的整合

    5.2.1 三种多配置Bean的整合方法

  1. 在创建 ApplicationContext 时,不指定具体的配置Bean,而是指定一个包扫描路径 basePackages
  • image.png
  • image.png
  • 类似的,整合xml配置文件时,也在创建 ApplicationContext 时,不指定具体的xml配置文件,而是模糊匹配
  • image.png
  1. 选定一个主配置Bean,然后把其他的配置Bean作为子配置Bean引入
  • 使用的是 @Import,注意,多个配置Bean需要在同一个包下
    • 可以创建对象
    • 也可以用于多配置Bean的整合
  • image.png
  1. 在工厂创建时,指定多个配置Bean的Class对象
  • 缺点

    • 耦合,需要写死配置Bean
    • 麻烦,需要穷举写
      1. ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig1.class, AppConfig2.class);

      5.2.1 跨配置进行注入

      应用配置Bean的过程中,不管使用哪种方式进行配置信息的汇总,其操作方式都是通过成员变量加入**@Autowired**注解完成
      示例:
  • 将 AppConfig2 中的对象注入到 AppConfig1 中 ```java @Configuration @Import(AppConfig2.class) public class AppConfig1 {

    @Autowired private UserDAO userDAO;

    @Bean public UserService userService() {

    1. UserServiceImpl userService = new UserServiceImpl();
    2. userService.setUserDAO(userDAO);
    3. return userService;

    } }

@Configuration public class AppConfig2 {

  1. @Bean
  2. public UserDAO userDAO() {
  3. return new UserDAOImpl();
  4. }

}

  1. <a name="puIBq"></a>
  2. ### 5.3 配置Bean与@Component相关注解的整合
  3. 整合方式
  4. - 在配置Bean中加上 `@ComponentScan`,扫描 `@Component` 家族的注解即可
  5. 注入方式
  6. - 使用的 `@Autowired`
  7. 创建 ApplicationContext,传入配置Bean就行
  8. - `ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig3.class);`
  9. ```java
  10. @Repository
  11. public class UserDAOImpl implements UserDAO{
  12. }
  13. @Configuration
  14. @ComponentScan("xxxx")
  15. public class AppConfig3 {
  16. @Autowired
  17. private UserDAO userDAO;
  18. @Bean
  19. public UserService userService() {
  20. UserServiceImpl userService = new UserServiceImpl();
  21. userService.setUserDAO(userDAO);
  22. return userService;
  23. }
  24. }

5.4 配置Bean与配置文件整合

配置方式

  • 使用 @ImportResource

注入

  • 使用 @Autowired

创建 ApplicationContext,传入配置Bean就行

  • ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig4.class); ```java

public class UserDAOImpl implements UserDAO{

}

@Configuration @ImportResource(“classpath:applicationContext.xml”) public class AppConfig4 { @Autowired private UserDAO userDAO; @Bean public UserService userService() { UserServiceImpl userService = new UserServiceImpl(); userService.setUserDAO(userDAO); return userService; } } ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig4.class); <a name="LfDet"></a> ## 6. 配置Bean底层实现原理 Spring在配置Bean中加入了@Configuration注解后,底层就会通过Cglib的代理方式,来进行对象相关的配置、处理 - 对带有 @Bean 注解的方法,进行了aop,用于控制对象的创建次数:方法调用一次,就会生成一个对象,代理后,调用配置Bean里的这个方法,就不会直接创建一个新对象,而是返回已经创建的对象 ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1637252256301-446ab20a-8e58-4232-9311-6213d396feaf.png#clientId=u2655fc71-f35c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=219&id=ud731326e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=558&originWidth=2316&originalType=binary&ratio=1&rotation=0&showTitle=false&size=617982&status=done&style=shadow&taskId=ud0109bd3-45e3-4655-8020-4513336b2ee&title=&width=907)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1637252073763-bc35941f-c751-454a-b1d4-d525e837c792.png#clientId=u2655fc71-f35c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=355&id=ue1534a2d&margin=%5Bobject%20Object%5D&name=image.png&originHeight=709&originWidth=1354&originalType=binary&ratio=1&rotation=0&showTitle=false&size=262654&status=done&style=shadow&taskId=ubec9ec53-1dfa-401d-a3bb-e44651c6587&title=&width=677) <a name="N8rVN"></a> ## 7. Spring 四维一体的开发思想 <a name="OXE3d"></a> ### 7.1 四维一体的概念 Spring开发一个功能的4种形式,虽然开发方式不同,但是最终效果是一样的。**因为最终使用的实现功能的类是一毛一样的** 1. 基于schema,既xml中的 `<context:`、`<aop:` 1. 基于特定功能注解(推荐) 1. 基于<bean 导入实现类 1. 基于 `@Bean` 注解 (推荐) <a name="Xd8LY"></a> ### 7.2 四维一体的开发案例 现在想将 properties 文件中的值,注入到bean中,实现方式有四种 <a name="iVfCx"></a> #### 7.2.1 基于 schema - 也即在 xml 中导入指定的 schema,让 xml 支持这些额外的标签(功能),来实现特定的功能 - 这里导入 <context: 的schema,支持 property-placeholder 的功能 - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1637253245260-e710d58b-cc8e-4d19-ac63-1c2bb423fa98.png#clientId=u2655fc71-f35c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=377&id=u09edd310&margin=%5Bobject%20Object%5D&name=image.png&originHeight=876&originWidth=2018&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1076060&status=done&style=shadow&taskId=ue39de973-5958-4579-a9de-67adea42d12&title=&width=869) <a name="pFFjv"></a> #### 7.2.2 基于特定功能注解 - 也即 Spring 提供的能实现这个功能的注解 - 这里使用 `@PropertySource` - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1637253362812-4d543b51-1496-473d-b9c6-8c7c8674fa5d.png#clientId=u2655fc71-f35c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=264&id=u9e202d09&margin=%5Bobject%20Object%5D&name=image.png&originHeight=602&originWidth=1065&originalType=binary&ratio=1&rotation=0&showTitle=false&size=442466&status=done&style=shadow&taskId=u28f55c8e-d64a-461a-a7d0-250cd3d6a2b&title=&width=467.5) <a name="S2pfG"></a> #### 7.2.3 基于原始<bean - 不管是xml导入还是注解,最后都需要Spring提供一个实现功能的类,因为xml的新schema需要类解析实现,注解也需要具体的实现类 - 这里的读取properties 文件的实现类为 PropertySourcePlaceholderConfigure,直接在 xml 中导入这个类为bean,并将properties 文件的路径作为属性注入即可,这样 Spring 有了这个Bean,就有了这个功能 - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1637253537469-bf8a3cf2-ef16-4086-baeb-9d8e94e35184.png#clientId=u2655fc71-f35c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=72&id=u05636e76&margin=%5Bobject%20Object%5D&name=image.png&originHeight=144&originWidth=1819&originalType=binary&ratio=1&rotation=0&showTitle=false&size=287981&status=done&style=shadow&taskId=ucd6c95ba-4329-492a-b648-c7beb68e59a&title=&width=909.5) <a name="Mh6Fb"></a> #### 7.2.4 基于 @Bean 注解 - 与第三点的原理一样,需要将 PropertySourcePlaceholderConfigure 作为Spring 的Bean - 只是第三点使用的xml配置文件,这里使用配置Bean - 注意,**classpath 路径使用对象 ClassPathResource** - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1637253661713-8dec6e5a-6c6b-48c5-b30c-2355eee2e116.png#clientId=u2655fc71-f35c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=224&id=ucf43dd3d&margin=%5Bobject%20Object%5D&name=image.png&originHeight=447&originWidth=1728&originalType=binary&ratio=1&rotation=0&showTitle=false&size=371315&status=done&style=shadow&taskId=u3a6d35f6-b36c-4bf6-b8d1-d64f48dbc03&title=&width=864) <a name="oj0d2"></a> ## 8. 纯注解版AOP编程 <a name="wxVKv"></a> ### 8.1 整体操作 1. 应用配置Bean 1. 注解扫描 完成以上两部后,就可以进行注解开发了 <a name="FRAe5"></a> ### 8.2 开发步骤 1. 原始对象 - 使用 @Component 注解,使其称为Spring beanjava @Service public class UserServiceImpl implements UserService{ } 2. 创建切面类 (额外功能 切入点 组装切面)java @Aspect @Component public class MyAspect { @Around(“execution( login(..))”) public Object arround(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println(“——aspect log ———“); Object ret = joinPoint.proceed(); return ret; } } `` 3. 配置Bean开启aop - 如果是xml配置文件,则是--》 这种就是四位一体中的基于schema 方式 - 现在使用配置Bean,则在配置Bean的类名上贴*@EnableAspectjAutoProxy--》 这种就是四位一体中的基于注解 方式 - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1774803/1637335530044-7e78e8b0-9a43-4b33-9c18-d3f75eecf587.png#clientId=ufe80eed9-ab9c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=119&id=u8f77df40&margin=%5Bobject%20Object%5D&name=image.png&originHeight=237&originWidth=869&originalType=binary&ratio=1&rotation=0&showTitle=false&size=160566&status=done&style=shadow&taskId=ue561b981-d7ac-4936-851f-dc8c3d73bfa&title=&width=434.5) <a name="mfwtJ"></a> ### 8.3 注解AOP细节分析 <a name="BX12H"></a> #### 8.3.1 代理创建方式的切换 - 基于 schema 开发方式中,可以通过 - 基于注解的开发方式,在@EnableAspectjAutoProxy注解中,指定proxyTargetClass属性即可切换 - true:Cglib;false:JDK - 默认为false,也就是 JDK -@EnableAspectjAutoProxy(proxyTargetClass = true)` - 默认都是 JDK image.png #### 8.3.2 SpringBoot AOP开发进一步简化 只需要Spring5中的前两步,也即
1. 原始对象
2. 创建切面类 (额外功能 切入点 组装切面)
配置Bean 的 @EnableAspectjAutoProxy(),SpringBoot已经默认弄好了 #### 8.3.3 SpringBoot AOP 默认实现不同 Spring AOP 代理默认实现 JDK SpringBOOT AOP 代理默认实现 Cglib ## 9. 纯注解版Spring+MyBatis整合 - 基础配置 (配置Bean)
```xml 1. 连接池

@Bean public DataSource dataSource(){ DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(“”); dataSource.setUrl(); … return dataSource; }

  1. SqlSessionFactoryBean

    classpath:com.baizhiedu.mapper/*Mapper.xml

    @Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){

    1. SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    2. sqlSessionFactoryBean.setDataSource(dataSource);
    3. sqlSessionFactoryBean.setTypeAliasesPackage("");
    4. ...
    5. return sqlSessionFactoryBean;

    }

  2. MapperScannerConfigure

    @MapperScan(basePackages={“com.baizhiedu.dao”}) —-> 配置bean完成 ```

  • 编码
    ```markdown
  1. 实体
  2. DAO接口
  3. Mapper文件 ```
    1. MapperLocations编码时通配的写法
    ```java //设置Mapper文件的路径 sqlSessionFactoryBean.setMapperLocations(Resource..); Resource resouce = new ClassPathResouce(“UserDAOMapper.xml”)

sqlSessionFactoryBean.setMapperLocations(new ClassPathResource(“UserDAOMapper.xml”));

classpath:com.baizhiedu.mapper/*Mapper.xml 一组Mapper文件

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources(“com.baizhi.mapper/*Mapper.xml”); sqlSessionFactoryBean.setMapperLocations(resources)

  1. <a name="3fdba1ed"></a>
  2. ###### 2. 配置Bean数据耦合的问题
  3. 使用 properties 文件解决

mybatis.driverClassName = com.mysql.jdbc.Driver mybatis.url = jdbc:mysql://localhost:3306/suns?useSSL=false mybatis.username = root mybatis.password = 123456 mybatis.typeAliasesPackages = com.baizhiedu.mybatis mybatis.mapperLocations = com.baizhiedu.mapper/*Mapper.xml

  1. ```java
  2. @Component
  3. @PropertySource("classpath:mybatis.properties")
  4. public class MybatisProperties {
  5. @Value("${mybatis.driverClassName}")
  6. private String driverClassName;
  7. @Value("${mybatis.url}")
  8. private String url;
  9. @Value("${mybatis.username}")
  10. private String username;
  11. @Value("${mybatis.password}")
  12. private String password;
  13. @Value("${mybatis.typeAliasesPackages}")
  14. private String typeAliasesPackages;
  15. @Value("${mybatis.mapperLocations}")
  16. private String mapperLocations;
  17. }
  18. public class MyBatisAutoConfiguration {
  19. @Autowired
  20. private MybatisProperties mybatisProperties;
  21. @Bean
  22. public DataSource dataSource() {
  23. DruidDataSource dataSource = new DruidDataSource();
  24. dataSource.setDriverClassName(mybatisProperties.getDriverClassName());
  25. dataSource.setUrl(mybatisProperties.getUrl());
  26. dataSource.setUsername(mybatisProperties.getUsername());
  27. dataSource.setPassword(mybatisProperties.getPassword());
  28. return dataSource;
  29. }
  30. @Bean
  31. public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
  32. SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
  33. sqlSessionFactoryBean.setDataSource(dataSource);
  34. sqlSessionFactoryBean.setTypeAliasesPackage(mybatisProperties.getTypeAliasesPackages());
  35. //sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("UserDAOMapper.xml"));
  36. try {
  37. ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
  38. Resource[] resources = resolver.getResources(mybatisProperties.getMapperLocations());
  39. sqlSessionFactoryBean.setMapperLocations(resources);
  40. } catch (IOException e) {
  41. e.printStackTrace();
  42. }
  43. return sqlSessionFactoryBean;
  44. }
  45. }

10. 纯注解版事务编程

  1. 1. 原始对象 XXXService
  2. <bean id="userService" class="com.baizhiedu.service.UserServiceImpl">
  3. <property name="userDAO" ref="userDAO"/>
  4. </bean>
  5. @Service
  6. public class UserServiceImpl implements UserService{
  7. @Autowired
  8. private UserDAO userDAO;
  9. }
  10. 2. 额外功能
  11. <!--DataSourceTransactionManager-->
  12. <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  13. <property name="dataSource" ref="dataSource"/>
  14. </bean>
  15. @Bean
  16. public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource){
  17. DataSourceTransactionManager dstm = new DataSourceTransactionManager();
  18. dstm.setDataSource(dataSource);
  19. return dstm
  20. }
  21. 3. 事务属性
  22. @Transactional
  23. @Service
  24. public class UserServiceImpl implements UserService {
  25. @Autowired
  26. private UserDAO userDAO;
  27. 4. 基于Schema的事务配置
  28. <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
  29. @EnableTransactionManager ---> 配置Bean
  1. 1. ApplicationContext ctx = new AnnotationConfigApplicationContext("com.baizhiedu.mybatis");
  2. SpringBoot 实现思想
  3. 2. 注解版MVC整合,SpringMVC中进行详细讲解
  4. SpringMyBatis --->DAO 事务基于注解 --> Service Controller
  5. org.springframework.web.context.ContextLoaderListener ---> XML工厂 无法提供 new AnnotationConfigApplicationContext

11. Spring框架中YML的使用

11.1 什么是YML

YML(YAML)是一种新形式的配置文件,比XML更简单,比Properties更强大。

11.2 Properties进行配置问题

  1. Properties表达过于繁琐,无法表达数据的内在联系.
  2. Properties无法表达对象 集合类型

    11.3 YML语法简介

  1. 1. 定义yml文件
  2. xxx.yml xxx.yaml
  3. 2. 语法
  4. 1. 基本语法
  5. name: suns
  6. password: 123456
  7. 2. 对象概念
  8. account:
  9. id: 1
  10. password: 123456
  11. 3. 定义集合
  12. service:
  13. - 11111
  14. - 22222

4. Spring与YML集成思路的分析
  1. 1. 准备yml配置文件
  2. init.yml
  3. name: suns
  4. password: 123456
  5. 2. 读取yml 转换成 Properties
  6. YamlPropertiesFactoryBean.setResources( yml配置文件的路径 ) new ClassPathResource();
  7. YamlPropertiesFactoryBean.getObject() ---> Properties
  8. 3. 应用PropertySourcesPlaceholderConfigurer
  9. PropertySourcesPlaceholderConfigurer.setProperties();
  10. 4. 类中 @Value注解 注入

5. Spring与YML集成编码
  • 环境搭建

    1. <dependency>
    2. <groupId>org.yaml</groupId>
    3. <artifactId>snakeyaml</artifactId>
    4. <version>1.23</version>
    5. </dependency>
    6. 最低版本 1.18
  • 编码
    ```java

  1. 准备yml配置文件
  2. 配置Bean中操作 完成YAML读取 与 PropertySourcePlaceholderConfigure的创建 @Bean public PropertySourcesPlaceholderConfigurer configurer() {

    1. YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
    2. yamlPropertiesFactoryBean.setResources(new ClassPathResource("init.yml"));
    3. Properties properties = yamlPropertiesFactoryBean.getObject();
    4. PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
    5. configurer.setProperties(properties);
    6. return configurer;

    }

  3. 类 加入 @Value注解 ```

6. Spring与YML集成的问题
  1. 1. 集合处理的问题
  2. SpringEL表达式解决
  3. @Value("#{'${list}'.split(',')}")
  4. 2. 对象类型的YAML进行配置时 过于繁琐
  5. @Value("${account.name}")
  6. SpringBoot @ConfigurationProperties