基本概念
- 依赖注入 dependency injection DI: 使相互协作的软件保持松耦合
- 优点 有助于应用对象之间的解耦
- 面向切面编程 aspect-oriented programming AOP 使遍布应用各处的功能 分离出来,形成可重用组件
- 若不使用: 如日志 事务 安全 这类关注点代码 会重复出现在多个组件中;修改困难; 组件会因与自身业务无关的代码 变得混乱
- 优点1:完全分离核心业务与关注点的逻辑,保证POJO的简单性
- 优点2:实现横切关注点 与 他们所影响的对象之间的解耦
- 简单Java对象 Plain Ordinary Java Object POJO
第一章:Spring 之旅
- Spring 简化Java 开发的4种策略
- 基于POJO的轻量级和最小侵入性编程 (不强迫应用继承框架的类 或 实现框架的接口,如传统的EJB就由侵入性)
- 通过依赖注入 和 面向接口 实现松耦合
- 依赖注入 可以通过构造器注入(注入的对象通过接口表明依赖关系,通过构造函数的参数注入;可以让被注入的对象 在毫不知情的情况下 注入不同的具体实现的对象 实现松耦合;(一种紧耦合的方式是,构造函数直接分配一个具体实现的对象))
- 通过切面 和 惯例 进行声明式编程
- 通过切面 和 模板 减少样板式代码(如JdbcTemplate)
- Spring 容器
- BeanFactory bean工厂
- ApplicationContext 应用上下文: 利用getBean 方法 获取 bean
- AnnotationConfigApplicationContext 从Java配置类 加载上下文
- AnnotationConfigWebApplicationContext 从Java配置类 加载Spring Web上下文
- ClassPathXmlApplicationContext 从类路径的XML 加载上下文
- FileSystemXmlapplicationcontext 从文件系统 加载上下文
- XMLWebApplicationContext 从web应用下的XML 加载上下文
- Bean的生命周期 P45
第二章: 装配Bean
- 三种装配Bean的机制
- 在XML 中显式配置
- 在Java 中显式配置
- 隐式的bean 发现机制 和 自动装配 (尽量自动装配)
- 自动装配的使用方式
- 组件扫描 component scanning
- 在要装配的bean 用@Component注解: 声明该类为组件类 并告知Spring要为这个类创建bean;默认Id为类名且首字母小写;指定名字@Component(”name”);也可以使用@Named代替@Component
- 在配置类使用@ ComponentScan注解 开启组件扫描;默认扫描配资料所在的包;可以设置需要扫描的包@ComponentScan(basePackages=“x1, x2”);也可以直接指定扫描的类或接口 @ComponentScan(basePackages=“x1.class”)
- 自动装配 autowiring
- @AutoWired 装配对象依赖的 其他对象;可以添加在构造器、属性的Setter方法;若匹配不到bean时会报错,可设置required=false 使匹配不到时不报错;@Inject可以替换@AutoWired
- 组件扫描 component scanning
- 通过Java代码装配Bean
- 声明一个类为配置类 @Configuration
- 在中 编写方法 new 出bean对象 并在这个方法上加@Bean注解
- Bean的Id与方法名一样 也可以通过@Bean("name") 设置
- @Bean的方法中 若有参数可以通过Bean注入,Spring也会自动注入
- Spring 会拦截对@Bean方法的调用,并返回Spring创建的Bean且默认为单例的
- 通过XML 配置P77
- XML 配置与JavaConfig配置互相引用 P92 @ImportResource
第三章 高级装配
- @Profile(“profile name”) 可以用在某类上 或某个 bean方法上 增加,代表激活该profile时才用该配置。profiles.active 配置环境
- @Conditional(CreateCondition.class) 某个Bean 在满足特定情况下 才会创建
- class可作为条件的实现类,其接口为:
- 当matches返回true时 条件通过,通过ConditionContext 可以知道Bean的定义、Bean是否存在、环境遍历的值,资源、类是否存在,AnnotatedTypeMetadata 可以知道某个Bean注解的方法上还有其他什么注解
- @Profile 就是用@Conditioanl 实现的
- 处理自动装配的歧义:若由多个bean可选,自动装配会出现起义,可用以下方法解决
- @Primary 标识首选的bean
- @Qualifier(“bean Id“) 在自动装配的地房 指定装配的bean
- 在@Bean标注的地方 和 自动装配的地方 同时使用@Qualifier(“特征性 描述性术语“) 避免beanId改变造成的bug
- 也可以通过 自定义注解 避免歧义
- Bean的作用域@Scope
- 单例 singleton 默认
- 原型 prototype 每次注入 都创建新的bean实例
- 会话 session 每个会话一个bean实例
- 请求 request 每个请求一个bean实例
- 使用会话 和 请求作用域
- 若某个单例服务 使用自动注入的方式 使用会话/请求类型 的Bean时,需要设置代理, 将调用委托给 会话/请求 作用域的真正的Bean
- 方式: 基于接口的代理 和 基于类的代码
- @Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.INTERFACES) 注入目标是接口
- @Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.TARGET_CLASS) 注入目标是具体的类,表明要以生成目标类拓展的方式代理
- 运行时注入bean的属性
- 使用Environment 获取properties中的属性
- 属性占位符 使用@Valuse(“${disc.title}“) 获取properties的属性(使用此方法 需要配置如下Bean)
- Spring表达式 语言SpEL (Spring Expression Language)P127
- 可通过beanID 引用Bean;可调用方法 和 访问对象的属性
- 可对值进行算术 关系 逻辑运算; 可进行集合操作 和 正则匹配
- 使用方法为@Valuse(“#{disc.title}“)
第四章 面向切面的Spring
- 横切关注点(cross-cutting concern): 散布在应用中多处的功能。如安全 日志 事务 缓存;横切关注点往往从概念上业务逻辑分离
- 面向切面编程(aspect-oriented programming AOP):将横切关注点 与 业务逻辑分离
- 横切关注点可以被模块化为特殊的类 称为 切面(aspect)
- AOP 优点:
- 每个横切关注点都集中在一个地方 而不是分散在多处
- 服务模块更简洁,只包含主要关注点 核心功能
- AOP 术语
- 通知 Advice
- 切面的工作称为通知
- 且通知定义了 切面何时使用
- 前置Before
- 后置 After
- 返回通知 After-returning 在目标方法成功执行之后调用通知
- 异常通知 After-throwing: 抛出异常后调用通知
- 环绕通知Around: 通知包裹被通知的方法,调用前后都执行自定义方法
- 切点 pointcut: 切点是指 需要匹配的一个或多个连接点(触发条件)
- 连接点 join point: 执行过程中插入切面的一个点: 可以是调用方法时、抛出异常时、修改字段时等
- 切面 aspect: 通知和切点的结合。 定义了 何时 何处 完成何种功能
- 引入 inroduction: 允许我们向现有类添加新方法或属性
- 织入 weaving: 织入是把切面应用到目标对象 并创建新的代理对象的过程
- 编译期: 需特殊的编译器 如AspectJ 织入编译器
- 类加器期: 目标类加载到JVM时被织入 在目标类被引入应用之前增强其字节码 如AspectJ 5 的加载时 织入 load-time weaving LTW
- 通知 Advice
- 运行期: 在运行的某个时刻织入 AOP容器为目标对象动态地创建代理对象 如Spring AOP
- Spring 对AOP 的支持局限于 方法拦截
- Spring 切面由 包裹目标对象的代理类实现
- 代理类处理方法的调用时 执行额外的切面逻辑 并调用目标方法
- Spring 运行时 才创建代理对象 不需要特殊编译器和类加载器 织入切面
- AspectJ 和 JBoss 支持 方法、字段和构造器 切点