Spring阅读笔记:Spring Core

Spring Core

1. Spring 总体了解

1.1 Spring作用:简化Java开发

1.1.1 基于POJO的轻量级实现最小侵入性编程

一个类使用Spring注解,但未实现或继承任何Spring规范的API,仍保留POJO模式。代码整洁

1.1.2 通过依赖注入实现松耦合

  • 紧耦合

    • 实现:在对象中具体实现或初始化了另外的依赖对象
    • 极大地限制了对象的能力
    • 不便于测试
  • 松耦合

    • 实现:构造器注入依赖对象
    • 在对象毫不知情的情况下,使用不同的依赖对象(前提是依赖对象实现了同一个注入的接口)
  • 具体使用

    • 创建POJO
    • 在XML或者使用Configuration注解,装载Bean,注入依赖
    • 在主程序中加载Application Context,获取Bean,调用方法

1.1.3 面向切面编程实现高内聚

  • 实现:使公共服务模块化,并以声明的方式将他们应用到组件中

  • 好处:使核心应用只关注自身业务,不必关心其他服务的实现细节

  • 具体使用

    • 创建POJO
    • 在XML或者使用Configuration注解,装载Bean,注入依赖
    • 在XML或者使用Configuration注解,定义切点(绑定组件),声明前置或后置通知(绑定方法)

1.1.4 通过模板封装消除样板化代码

1.2 Spring组件:Bean

1.2.1 BeanFactory(不推荐)

1.2.2 Application Context

  • Annotation Config Application Context
  • Annotation Config Web Application Context
  • Class Path Xml Application Context
  • File System Xml Application Context
  • Xml Web Application Context

1.2.3 Bean的生命周期

  1. Spring对Bean进行实例化
  2. Spring将值或者Bean的引用注入Bean对应的属性中
  3. 如果Bean实现了BeanNameAware接口,Spring将Bean的id传给setBeanName()
  4. 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory(),传入BeanFactory容器实例对象
  5. 如果Bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext(),传入Bean所在的应用上下文
  6. 如果Bean实现了BeanPostProcessor接口,Spring将调用postProcessBeforeInitialization()
  7. 如果Bean实现了InitializingBean接口,Spring将调用afterPropertiesSet()
  8. 如果Bean使用了init-method,也会被调用
  9. 如果Bean实现了BeanPostProcessor接口,Spring将调用postProcessAfterInitialization()
  10. 此时,Bean已经准备就绪,一直存在于应用上下文中,直到该应用上下文被销毁
  11. 如果Bean实现了Dispos ableBean接口,Spring将调用destroy()
  12. 如果Bean使用了destroy-method,也会被调用

2. 面向切面

2.1 AOP基础概念

2.1.1 AOP作用

在一个地方定义通用功能,通过声明方式定义这个功能要在何时何处做何事,而无需修改受影响的类

2.1.2 AOP术语

  • 通知:定义切面是什么,何时使用
  • 连接点:可以是调用方法时、抛出异常时、修改字段时
  • 切点:定义连接点的范围,即在何处
  • 切面:通知+切点
  • 引入:向已有的类添加新属性和方法
  • 织入:把切面应用到目标对象并创建新的代理对象的过程
    • 编译期织入(AspectJ的织入编译器)
    • 类加载期织入(ClassLoader)
    • 运行时织入(SpringAop)

2.1.3 Spring的AOP

  • Spring通知通过Java编写
  • Spring在运行时通知对象
  • Spring只支持方法级别的连接点

2.2 通过切点来选择连接点

2.2.1 切点编写

  • execution(* packageName.className.method(..))
  • 限制条件:arg()、this()、target、within()
  • 连接:and、or、not、&、|、!

2.2.2 在切点中选择Bean

bean()

2.3 创建切面的两种方式

2.3.1 使用注解创建切面

@Aspect定义切面
  • @After
  • @Before
  • @AfterThrowing
  • @AfterReturning
  • @Around
    • 声明的方法必须有ProceedingJoinPoint参数,且需要在try中合适位置调用jp.proceed(),代表被通知方法调用
  • @Pointcut声明频繁使用的切点表达式,定义切点时直接使用被@Pointcut声明的方法即可
开启AspectJ自动代理
  • 在JavaConfig配置类上添加@EnableAspectJ***
  • 在XML中添加<aop:aspectj-*** />
处理通知中的参数

切点表达式中使用arg(),@Pointcut声明方法带参数,再在合适时机调用

引入新功能

@DeclareParents(value, defaultImpl)声明要引入的接口

  • value:指定哪种类型的Bean要引入该接口

  • defaultImpl:指定实现引入接口功能的类

2.3.2 使用XML创建切面

3. 装配Bean

3.1 自动化装配

创建接口,创建实现该接口且实现@Component的Bean类

  • Bean的id可以在@Component中声明
  • 在构造器或Setter方法上使用@Autowired,为Bean注入依赖Bean

在JavaConfig或XML中开启组件扫描配置

  • 在@ComponentScan中声明basePackages数组,里面填充包名
  • 在@ComponentScan中声明basePackageClasses数组,里面填充类名,自动扫描类所在的包

3.2 JavaConfig装配

  • 使用@Configuration创建配置类
  • 在JavaConfig中使用@Bean创建方法,返回值是Bean对象(通过@Bean中name参数设置id)
  • 为Bean注入依赖:使用参数为被依赖的Bean对象创建方法的方法,创建Bean对象
    • 被依赖的Bean对象的创建方法并未真的调用,因为该方法也是@Bean。保证多次调用返回的是同一个Bean对象
    • 创建依赖Bean的方法也可以传入被依赖的Bean对象,此对象可以有三种方式装配(自动、Java Config、XML)

3.3 XML装配

3.3.1 XML配置规范

3.3.2 声明Bean

3.3.3 构造器注入

  • 依赖Bean注入

  • 字面量注入

  • 集合注入

  • 注入方式:、c名称空间

3.3.4 Setter注入

  • 依赖Bean注入
  • 字面量注入
  • 集合注入
  • 注入方式:、p名称空间

4. 高级装配

4.1 Profile适应不同环境

目的

在不同环境中某个Bean会有所不同,我们需要选择最合适的配置

做法

使用Bean Profile,在运行时根据环境决定该创建哪些Bean和不创建哪些Bean

具体实现

Java Config
  • 在@Configuration配置类上使用@Profile(),表示这个配置类中的所有Bean都在该Profile激活时创建
  • 在配置类中的@Bean创建方法上使用@Profile(),表示单独这个Bean在Profile激活时创建
XML

配置<beans>元素中的profile属性,也可重复使用配置多个profile

激活Profile

  • spring.profiles.active

  • spring.profiles.default

  • 激活方式

    • 作为DispatcherServlet的初始化参数
    • 作为Web应用的上下文参数
    • 作为JNDI条目
    • 作为环境变量
    • 作为JVM的系统属性
    • 在集成测试类上,使用@ActiveProfiles注解

4.2 Conditional条件化装载

需求

  • 希望一个或多个Bean只有在应用的类路径下包含特定的库时才创建
  • 希望某个Bean只有当另外某个特定的Bean也声明了之后才会创建
  • 希望只有某个特定的环境变量设置后才创建

实现

  • 在Java Config配置类的@Bean创建方法上,使用@Conditional注解,注解中传入实现了Condition接口的类
  • 创建Condition接口的实现类,实现matches方法

详解matches方法的参数

ConditionContext接口
  • 通过getRegistry()返回的BeanDefinitationRegistry检查Bean定义
  • getBeanFactory()
  • getEnviroment()
  • getResourceLoader()
  • getClassLoader()
AnnotatedTypeMetadata接口
  • isAnnotated(),判断带@Bean的方法是不是还有其他特定注解
  • getAnnotationAttributes(),检查@Bean方法上其他注解的属性

4.3 处理自动装配的歧义性

标识首选

  • 在@Component类上使用@Primary设为首选
  • 在Java Config中@Bean方法上使用@Primary
  • 在XML中将<bean>的primary属性设为true

限定范围

使用Bean自动生成的id限定

在@Autowired的Setter方法上使用@Qualifier限定注入Bean的id

  • 导致被依赖的Bean的id和依赖的Bean紧耦合,修改重构时无法自动匹配
创建自定义限定符(面向特性)
  • 在@Component类上添加@Qualifier限定范围
  • 在@Autowired注入依赖方法上添加@Qualified注入限定范围内的Bean
  • 使用Java Config也可以将@Bean和@Qualifed一起用
创建自定义限定符注解(面向特性)
  • 使用@Target()、@Retention()、@Qualifier自定义注解
  • 在@Component类上添加多个自定义注解

4.4 Bean的作用域

单例Singleton

整个应用中只创建一个(默认)

原型Prototype

  • 功能:每次注入或者通过Spring应用上下文获取时,都会创建一个新的Bean
  • 组件扫描配置
    • 在@Component类上添加@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
  • Java Config配置
    • 在@Bean方法上添加@Scope(ConfigurableBeanFactory.SCOPE_PRO TOTYPE)
  • XML 配置
    • <bean>中设置scope属性值为prototype

会话Session

  • 功能:在Web应用中,每个会话创建一个Bean
  • 在@Component类上使用@Scope,设置value、proxyMode
  • 在XML中将<bean>的scope属性设为session,增加<aop:scoped-proxy>
    • 默认是创建目标类的代理
    • 可以将proxy-target-class设为false,创建基于接口的代理

请求Request

  • 功能:在Web应用中,每次请求创建一个Bean
  • 用法与会话类似

4.5 运行时值注入

目的

将具体值提取到配置文件中,运行时加载,避免硬编码

Spring中的Environment

  • 与属性相关方法:getProperty()、getRequiredProperty()、getPropertyAsClass()

  • 与Profile状态相关方法:getActiveProfiles()、getDefaultProfiles()、accpetsProfiles()

注入方式

  • 属性占位符

    • 组件扫描自动装配
      • 在@Component类的构造器中使用@Value(“${name}”)获取配置文件中的值
    • 为使用占位符,需配置一个Bean是PropertySourcesPlaceholderConfigurer
  • Spring表达式语言(SpEL)

全部评论

相关推荐

02-11 17:51
腾讯_TEG_技术
点赞 评论 收藏
分享
01-16 18:34
四川大学 Java
欢迎加入AI:没有啥稳定不稳定,一切都源于业务快速发展还是收缩。我当年一开始去的央企,业务不赚钱,也贼卷,慢慢就开始优化了。。。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务