使用Spring简化 JAVA 开发
为了降低 Java 开发的复杂性,Spring 采取了以下 4 种关键策略:
- 基于 POJO (Plain Old Java Object) 的轻量级和最小侵入性编程;
- 通过依赖注入和面向接口实现松耦合;
- 基于切面和惯例进行声明式编程;
- 通过切面和模板减少样板式代码;
而IOC(控制反转)和AOP(面向切面编程)是整个Spring框架的核心。
IoC控制反转
IoC(Inverse of Contro)控制反转,把实例化对象的权限交给Bean配置。DI—Dependency Injection依赖注入,它是一种降低对象耦合关系的一种设计思想。
Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。
依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,只需要通过简单XML配Bean,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
一、XML配置Bean实现控制反转
1、导入核心jar包
4+1:4个核心(beans、context)+1个依赖(commons-logging)
- spring-beans-5.2.3.RELEASE.jar
- spring-context-5.2.3.RELEASE.jar
- spring-core-5.2.3.RELEASE.jar
- spring-expression-5.2.3.RELEASE.jar
- commons-logging-1.2.jar
2、编写一个简单的实例
定义接口:ISpring.java
1 | package org.example.data; |
实现类1:SpringAdd.java
1 | package org.example.data; |
3、装配Bean
装配Bean获取对象,将实例化控制权限反转。而装配Bean有两种方式,各有优劣:
- 注解:是一种分散式的元数据,与源代码紧绑定。
- xml:是一种集中式的元数据,与源代码无绑定。
这里以通用性较强的XML为例。
主配置文件默认放在根目录下:applicationContext.xml
1 |
|
4、进行单元测试
单元测试类:Test.java
1 | package test; |
输出结果:
1 | 第一次实现。 |
DI依赖注入实现
DI能够让相互协作的软件组件保持松散耦合,而面向切面编程(aspect-oriented programming,AOP)允许你把遍布应用各处的功能分离出来形成可重用的组件。系统由许多不同的组件组成,每一个组件各负责一块特定功能。
依赖注入实现
1、创建依赖类:DIInput.java
1 | package org.example.data; |
2、装配Bean:applicationContext.xml
1 |
|
3、注入依赖:SpringAdd.java
1 | package org.example.data; |
4、运行测试类 Test.java 输出:
1 | 第一次实现 |
基于注解自动装配Bean
自动装配省去了传入依赖注入到Bean的这一步:
1 | <constructor-arg ref="diInput"/> <!-- 传入依赖 --> |
而xml的自动装配很简单,只需要在 bean 标签加一个 autowire=”” 属性就行,例如:
1 | <bean id="add" class="org.example.data.SpringAdd" autowire="byType"></bean> |
这里主要讲基于注解的自动装配:
从 Spring 2.5 开始就可以使用注解来配置依赖注入,注解默认情况下在 Spring 容器中不打开。如果需要使用注解配置Bean的注入,在使用注解之前,我们将需要在我们的 Spring 配置文件中启用它。
使用 context:annotation-config 元素开启注解模式。
或者,使用 context:component-scan 元素——开启自动扫描全注解模式。两者的区别是:
context:annotation-config 是用于激活那些已经在spring容器里注册过的 bean(无论是通过xml的方式还是通过package sanning的方式)上面的注解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 开启注解模式 -->
<context:annotation-config/>
<!-- 这种相当于半注解模式,仍然需要定义 bean -->
<!-- bean 定义放在 <context:annotation-config/> 之后-->
<bean id="add" class="org.example.data.SpringAdd"></bean>
<bean id="diInput" class="org.example.data.DIInput" ></bean>
</beans>
- context:component-scan 除了具有 context:annotation-config 的功能之外,context:component-scan 会扫描指定的包及其所有的子包,并查找出能够自动注册为 Spring Bean 的类。base-package 属性标识了 context:component-scan 元素所扫描的包。
这意味着不使用 bean 元素,Spring应用大多数(或者所有) Bean 都能够实现定义和装配。
1 |
|
半注解 context:annotation-config 模式几个重要的注解:
- @Required:注解应用于 bean 属性的 setter 方法。
- @Autowired:注解可以应用到 bean 属性的 setter 方法,非 setter 方法,构造函数和属性。
- @Qualifier:通过指定确切的将被连线的 bean,@Autowired 和 @Qualifier 注解可以用来删除混乱。
- JSR-250 Annotations:Spring 支持 JSR-250 的基础的注解,其中包括了 @Resource,@PostConstruct 和 @PreDestroy 注解。
xml配置文件中开启 context:component-scan 全注解模式后可使用Spring提供了进一步的构造型注释:@ Component,@ Repository,@ Service和@Controller。
- @Component 是任何Spring托管组件的通用构造型。
- @ Repository,@ Service和@Controller是@Component的特化,用于更具体的用例(分别在持久层,服务层和表示层中)。
因此,您可以使用@Component来注释组件类,但是通过使用@ Repository,@ Service或@Controller来注释组件类,您的类更适合于通过工具进行处理或与方面相关联。例如,这些构造型注释成为切入点的理想目标。 @ Repository,@ Service和@Controller在Spring框架的将来版本中也可以带有其他语义。因此,如果在服务层使用@Component或@Service之间进行选择,则@Service显然是更好的选择。同样,如前所述,@ Repository已被支持作为持久层中自动异常转换的标记。
Spring在加载Bean的时候,有时候会用到order注解。顾名思义,Order是顺序,此注解可操作于类、方法、字段,当作用在类时,值越小,则加载的优先级越高!
小结:
使用注解虽然省去了一些 bean 的配置,但却在一定程度增加了维护成本。
使用XML配bean的方式,虽然配置繁琐,但集中管理了依赖,一定程度上较少了维护的成本。
具体情况具体分析,使用那种装配方式视情况而定。
AOP面向切面编程
Spring 框架的一个关键组件是面向切面的编程(AOP)框架。面向切面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样的常见的很好的切面的例子,如日志记录、审计、声明式事务、安全性和缓存等。
AOP术语:
切面(@Aspect):标记一个切面,即横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象(切面模块)。
通知(Advice):切面必须要完成的工作。
目标(Target):被通知的对象,核心业务逻辑。
代理(Proxy):向目标对象应用通知之后创建的对象,整合各切面的代理对象。
连接点(Joinpoint):程序执行的某个特定位置。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。
切点(@Pointcut):每个类都拥有多个连接点,给重复的注解/切点定义表达式
Spring 切面可以使用下面提到的五种通知工作:
通知 | 描述 |
---|---|
前置通知(@Before) | 在一个方法执行之前,执行通知。 |
后置通知(@After) | 在一个方法执行之后,不考虑其结果,执行通知。 |
返回后通知(@AfterReturn) | 在一个方法执行之后,只有在方法成功完成时,才能执行通知。 |
抛出异常后通知(@AfterThrowing) | 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。 |
环绕通知(@Around) | 在建议方法调用之前和之后,执行通知。 |
Spring 支持 @AspectJ annotation style 的方法和基于模式的方法来实现自定义切面。这两种方法已经在下面两个子节进行了详细解释。
方法 | 描述 |
---|---|
XML Schema based | 切面是使用常规类以及基于配置的 XML 来实现的。 |
@AspectJ based | @AspectJ 引用一种声明切面的风格作为带有 Java 5 注释的常规 Java 类注释。 |
Spring AOP 模块提供拦截器来拦截一个应用程序,例如,当执行一个方法时,你可以在方法执行之前或之后添加额外的功能。
纯注解模式实现AOP
使用纯注解模式给上面的实例,加入一个前置日志模块(切面)
1、创建一个日志切面类:LoggingAspect.java
1 | package org.example.data; |
2、使 Aspectj 注解起作用:applicationContext.xml
1 |
|
在同一个连接点上应用不止一个切面时,除非明确指定,否则它们的优先级(加载顺序)是不确定的。切面的优先级可以通过实现 Ordered 接口或利用 @Order 注解指定。
实现 Ordered 接口,getOrder() 方法的返回值越小,优先级越高
若使用 @Order 注解,序号出现在注解中,如@Order(0),序号越小拥有越高优先级,可为负数。
基于XML的AOP配置
有了上述概念,如果不使用AOP注解,那基于XML的AOP配置其实也很容易理解。
这里提供一个XML配置文件以供参考:applicationContext.xml:
1 |
|
Maven管理的项目结构图:
2020年5月2日完结
以上内容,仅供参考,转载请注明出处。