Spring 入门之 IOC 与 AOP
Spring 是目前最流行的 Java 开发框架, Java 企业开发中的 SSH 或者 SSM 都与 Spring 有关。 Spring 最根本的使命是简化 Java 开发。
基于这一使命,Spring 有了以下 4 中关键策略:
-
-
基于 POJO 的轻量级和最小侵入式编程;
-
-
-
通过依赖注入和面向接口编程实现松耦合;
-
-
-
基于切面和惯例进行声明式编程;
-
-
-
通过切面和模板减少样板式代码。
-
Spring 核心: IOC 与 AOP
这里简单的介绍下 Spring 最为核心的两个特性: IOC 和 AOP
IOC 控制反转容器
IOC(Inverse Of Control) 容器: 控制反转意思是应用程序不再负责维护对象 (Java 中主要是对象的创建,初始化),而将这部分工作交给 IOC 容器。 应用程序直接从 IOC 容器中获取到所需要的对象, 只负责使用对象。
这是一种分工合作的思想, 将**对象的维护和使用进行了分工**,应用程序只负责使用对象。
DI(Dependency Injecttion) 依赖注入在 Spring 中一般作为 IOC 容器的同义词 (PS. Spring 实战第 4 版 一书就使用的是 DI). 个人理解, DI 是通过 IOC 容器来实现的, IOC 容器不仅可以生成 Java 对象, 还可以组装 Java 对象之间的依赖关系, 这正式 IOC 强大的地方。 如果你有一个对象 A , 它持有对象 B 的引用即 A 依赖 B, 那当你使用 Spring IOC 容器获取 A 对象时, A 引用的 B 对象也已经被 IOC 容器准备好并且赋值给 A 中的属性。
Spring 依赖注入 (DI) 方式
Spring 的依赖注入一般有两种方式:
-
-
设值注入
-
IOC 容器调用 setter 方法将依赖注入到目标对象
-
-
构造注入
-
依赖作为构造器的参数,通过构造函数注入到目标对象
Spring 中的对象 Bean
bean 的作用域
Spring 中对象 (Bean) 的作用域:
-
-
Singleton: 单例,一个 bean 容器中只存在一个, 默认行为;
-
-
-
prototype: 每次向 bean 容器请求都会创建一个实例;
-
-
-
request: 每次 http 请求都会创建一个实例,并且仅在当前 request 内有效, 只在 web-aware Spring ApplicationContext 的上下文中有效
-
-
-
session : 每个会话会创建一个实例,并且在当前会话内有效,只在 web-aware Spring ApplicationContext 的上下文中有效
-
-
-
Global Session: 类似 session, 只在 portlet 环境中有效, 非 portlet 环境中相当于 session。只在 web-aware Spring ApplicationContext 的上下文中有效
-
bean 的生命周期
Bean 的生命周期:
-
-
定义
-
-
-
初始化
-
实现 InitializaingBean 接口或者配置 init-method 方法
-
-
使用
-
-
-
销毁
-
实现 DesposableBean 接口或者配置 detroy-method 方法
bean 的自动装配
Autowiring(自动装配):
-
-
No, 默认行为
-
-
-
byName
-
-
-
byType
-
-
-
Constructor
-
Spring 中可以开启自动装配功能, 这样不需要在 bean 的配置中显式的声明依赖对象,Spring 会自动进行依赖注入,通过配置的自动装配类型。
AOP 面向切面编程
AOP(Aspect Oriented Programming, 面向切面编程), 通常用于分离业务逻辑和系统服务,实现松耦合
一般由预编译和动态代理两种实现方式,**SpringAOP 是使用动态代理**实现的。
Aspect(切面): 一个关注点的模块化,会横切多个对象。
切面是一些系统级的服务, 每个业务模块都需要, 例如日志,性能统计,安全控制,事物处理等。
(PS. 事物, 一组操作要么一起成功要么一起失败)
PointCut(切点): 匹配连接点的断言
连接点就是切面和业务模块相连的地方, 即实际要触发执行切面动作的业务模块代码位置。
Advice(通知):切面在连接点要执行的动作,有以下几种类型:
-
-
Before
-
-
-
After returning
-
-
-
After throwing
-
-
-
After
-
-
-
Around
-
Spring bean 装配方式配置
Spring 装配 Bean 的方式:
-
-
在 XML 中进行显示配置
-
-
-
在 Java 中进行显示配置 (注解)
-
-
-
隐式的 bean 发现机制和自动装配
-
Spring in Action 一书推荐优先使用组件扫描和自动装配, 其次是 Java 配置, 再是 XML 配置。
Spring Java 配置方式装配 Bean 的常用注解:
@Component : 表明该类会作为组件类,Spring 要为这个类创建 bean; 可以带一个字符串参数,显示指定 bean ID.
如果不明确设置 beanid , Spring 会根据类名指定一个, 即将类名的第一个字母小写作为 ID.
@Configuration : 表明这是一个 Spring 配置类
@ComponentScan: 开启组件扫描,扫描所有用 @Component 标记的类, 默认扫描与配置类相同的包, 可以用 basePackage 或者 basePackageClasses 属性来指定扫描的路径
@Autowired : Sping 自动装配, 可以用于构造器和属性的 setter 方法上, required 属性默认为 true, 意味着 Spring 在创建应用上下文时, 如果没有匹配的 bean 会抛出异常; 该属性设置为 false 时, 如果没有批评的 bean , Spring 会让这个 bean 处于未装配的状态, 需要谨慎使用。
自动组件扫描和自动装配有时行不通, 例如需要将第三方库中的组件装配到应用中, 这时需要显示的配置 Bean.
@Bean, 在 javaConfig 中声明 bean(类似在 xml 中声明 bean)
@Configuration
@ComponentScan(basePackageClasses = {Sgtpeppers.class})
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers() {
return new Sgtpeppers();
}
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
@Bean
public CompactDisc sgtPeppers() {
return new Sgtpeppers();
}
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
@Configuration
@ComponentScan(basePackageClasses = {Sgtpeppers.class})
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers()
{
return new Sgtpeppers();
}
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc)
{
return new CDPlayer(compactDisc);
}
}
@Bean 注解可以采用任何有必要的 Java 功能来产生 bean, 构造器和 Setter 方法是最常见的, 可能性仅仅受 Java 语言的限制。
@Profile, 用于实现不同的环境不同的配置
@Conditional, 可以用到带有 @Bean 注解的之上, 实现条件化 Bean, 给定条件为 true, 就会创建这个 bean.
AOP 定义如下:
<?xml version="1.0"encoding="UTF-8"?><?xml version="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
<beanid="User"class="User"scope="singleton" init-method="init"destroy-method="destory1">
<!--constructor-arg ref="IPhone"/ -->
<property />
</bean>
<beanid="IPhone"class="Iphone"/>
<beanid="MyAspect"class="MyAspect"/>
<aop:config>
<aop:aspectid="Aspect"ref="MyAspect">
<aop:pointcutid="MyPointCut"
expression="execution(**.recordMessage(..))"/>
<aop:before pointcut-ref="MyPointCut"
method="monitorAspect"/>
</aop:aspect>
</aop:config>
<!--more bean definitions go here -->
</beans>
常见问题:
什么是 DI 依赖注入?
把有依赖关系的类放到容器中,解析出这些类的实例,就是依赖注入。目的是实现类的解耦。
实例:Class A 中用到了 Class B 的对象 b,一般情况下,需要在 A 的代码中显式的 new 一个 B 的对象。采用依赖注入技术之后,A 的代码只需要定义一个私有的 B 对象,不需要直接 new 来获得这个对象,而是通过相关的容器控制程序来将 B 对象在外部 new 出来并注入到 A 类里的引用中。这样做有什么好处呢?
什么是 AOP 面向切面编程?
在软件业,AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。