这里的 Spring 指的还是 SpringFramework ;Spring 是做什么的上一篇中已经说的很详细了,也主要是说的怎么用,这篇主要是对上篇的知识补充,多是理论的补充,有些重复内容,写的也很混乱….
Spring AOP 详细的整理已出!强行下一篇就是!
概述
Spring 提供了一站式解决方案,它主要包含六大模块:
- Spring Core
核心功能:IoC 容器,解决对象的创建及其依赖关系
jar 包组成由:spring-expression-4.3.11.RELEASE.jar
spring-beans-4.3.11.RELEASE.jar
spring-core-4.3.11.RELEASE.jar
commons-logging-1.2.jar
spring-context-4.3.11.RELEASE.jar
- Spring Web
这是 spring 对 web 模块的支持,也就是说可以与 Struts 整合,把 Action 的创建交给 spring;
或者可以使用自家的 springMVC,相关的 jar 包有:spring-web-4.3.11.RELEASE.jar
spring-webmvc-portlet-4.3.11.RELEASE.jar
spring-webmvc-4.3.11.RELEASE.jar
spring-websocket-4.3.11.RELEASE.jar
- Spring DAO
这是 spring 对 jdbc 的支持,比如 JdbcTemplate 模板工具类,相关的 jar 包有:spring-jdbc-4.3.11.RELEASE.jar
spring-oxm-4.3.11.RELEASE.jar
spring-jms-4.3.11.RELEASE.jar
spring-tx-4.3.11.RELEASE.jar
spring-orm-4.3.11.RELEASE.jar
- Spring ORM
这是 spring 对 ORM 的支持,既可以与 hibernate 整合,也可以选择使用 spring 对 hibernate 操作的封装 - Spring AOP
上篇中说过了,对 AOP 的支持,也就是面向切面编程,相关的 jar 包有:spring-aop-4.3.11.RELEASE.jar
spring-instrument-4.3.11.RELEASE.jar
spring-aspects-4.3.11.RELEASE.jar
spring-instrument-tomcat-4.3.11.RELEASE.jar
- Spring EE
这是 spring 对 javaEE 其他模块的支持
Bean的创建
关于 Bean 的生命周期在上一篇说的非常非常详细了,总结就是:如果你设置了单例模式,也就是默认的,并且懒加载没有开启(默认)那么它会在启动的时候创建(实例化);但是如果设置的是 prototype 就是在获取的时候才进行实例化
使用构造函数
在装配 Bean 的时候,上一篇使用的是 property 标签,通过相应的 Set 方法进行注入,其实还可以使用 constructor-arg 标签来进行初始化,它们的区别是一个是通过 set 方法,一个是通过构造函数(不一定非要是构造,其他带参数的方法也行,比如下面要说的工厂方式),默认用的就是无参的构造函数:
1 | <bean id="student" class="com.rc.sp.Student"> |
但是需要注意下顺序,如果顺序和构造函数不同要使用 index (从 0 开始)或者 name 属性来指定;name 省略其实也可以
使用工厂
创建 bean 的方式中,除了使用构造函数常见的还有就是使用工厂模式了,并且分为静态工厂和实例工厂;如果使用的不是静态方法,那么就需要先创建工厂对象然后通过方法进行获取实例:
1 | <!-- 先创建工厂对象 --> |
如果使用的是静态的,那么就不需要创建工厂对象了:
1 | <!-- 使用工厂的方法创建实例 --> |
p命名空间
p 命名空间是用来简化属性注入的,就是说让我们少写一些 property 标签,使用之前需要先引入 xmlns,但是没有对应的 Schema 文件,因为没有办法预先知道用户使用的属性名称,所以也就无法定义 Schema 文件。
所以说只需要加入 xmlns:p="http://www.springframework.org/schema/p"
就可以使用了,具体的使用方式是:
1 | <bean id="rob" class="..TestBean" p:name="Rob Harrop" p:spouse-ref="sally"/> |
这样是不是简洁多了呢,使用 p:name
直接注入其 name 属性的值,p:spouse-ref
就是注入 spouse 属性,不过是引用的其他 bean,当然使用的还是 set 方法来进行注入的。
AOP编程
Spring中的AOP 文章已经整理完,关于 AOP 的详细信息推荐去看看!
在 Spring 中的 AOP 处理中,如果加入容器的目标对象有实现接口就使用 JDK 代理,如果目标对象没有实现接口就使用 Cglib 代理。
另外补充下,最早做 AOP 的是 Eclipse 的 Aspect,Spring 也是引用的它
代理对象的创建-Cglib
不知道以前是否写过,在创建代理对象的时候,如果目标对象有接口那么用 JavaAPI 的那一套就可以创建代理对象了,但是如果目标对象没有实现接口,那么就白搭了,好在有一个叫 Cjlib 的库,它被许多 AOP 框架使用,它就是为了解决这个问题,具体的介绍自行搜索,这里只说明它的作用
它是通过继承的方式来实现的,首先有一个通用的工具类 Enhancer,通过这个工具类设置父类为我们的目标对象,然后设置回调函数,最后创建一个子类返回就可以了。
1 | public class ProxyFactory implements MethodInterceptor{ |
怎么用就不用说了吧…..因为本质是采用的继承的方式,所以有几个注意事项:
- 代理的类不能为 final,否则报错
- 目标类的方法不能为 final 或者 static,否则不会进行拦截
当然不要忘记了代理类实现接口。
JDK 中的代理一般是 $
开头,Cglib 一般就是代理对象名开头后面再加一些东西
关注分离
前面也是提到过这个词的,什么关注分离思想,关注点是什么呢?其实指的就是重复代码;在一些方法中,我们可能需要写许多重复代码,而真正的核心代码就只有几行。
比如 DAO 层中的 session 处理的代码,又是事务又是连接的,每个方法都需要写,这些代码就可以看作是关注点,我们要做的就是分离它
使用代理,可以在运行期间,执行核心业务代码的时候动态植入关注点代码
AOP 的目标就是让关注点代码和业务代码进行分离
对比上一篇“专业”的解释,我们来一把通俗的介绍,当然可能并不准确;
通知/增强: 就是 关注点,也就是重复的代码;
切面: 就是关注点形成的类,也就是说很多重复的代码就可以形成一个切面;
切入点:运行时在哪里织入切面类的代码,拦截的作用;
面向切面编程:对很多重复的代码进行抽取,然后在运行的时候往业务方法上进行织入切面类代码。
Spring中使用AOP
提起 AOP 那其实要说下 Aspect 了,它值得去单独去学习,也不少的内容,这里就只是简单的说下 Spring 中常用的几种形式,如果有必要,会单独开一篇写 AspectJ ,并且一篇都不一定写的完,大体浏览了下,内容确实不少,慢慢来吧
首先必要的在 xml 中引入命名空间和相关 jar 包就不细说了,记得配置开启注解,这个比较省事,大都采用这种形式吧
1 | <beans xmlns="http://www.springframework.org/schema/beans" |
上一篇中使用的 XML 配置,然后下面简单介绍下注解的使用:
- @Aspect
声明该类是一个切面, Spring 将会把它当作一个特殊的 Bean(一个切面),也就是说不对这个类本身进行动态代理 。 - @Pointcut
定义切入点,切入点的名称就是此方法名,也就是确定拦截哪些方法,就是为哪些类生成代理对象
参数为切入点表达式:@Pointcut("execution (* com.bfchengnuo.service..*.*(..))")
第一个*
指的是任何返回值,(..)
指的是任何参数,..
指的是本包、以及及其子包下,多个可以使用||
分割,甚至可以在前面加!
,其他的应该就更好理解了;需要注意的是最后一定是定义到方法的!
其他的注解就没什么难度了,来看个栗子就都知道了:
1 |
|
详细的理论知识补充可以去参考 Spring中的AOP 一文
对JDBC的支持
在刚开始的时候已经看到了,Spring 中有个模块就是 Spring DAO,说明了 Spring 对 JDBC 的支持还是很好的,;例如体现在对 C3P0 连接池的支持上,甚至比 Hibernate 都好,并且有 JdbcTemplate 模板工具类(类似 DBUtils)。
下面配置 dataSource 的方式应该都比较熟悉了,使用 C3P0:
1 | <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> |
并且顺便把 JdbcTemplate 也进行实例化了,它需要一个数据域,可以 set 方法指定,也可以构造函数给它;
至于它怎么使用,看个栗子就都知道了,会感觉很熟悉吧….
1 | public class UserDAOImpl extends JdbcDaoSupport implements IUserDAO { |
用户自己编写DAO 只需要继承 JdbcDaoSupport, 就可以注入 JdbcTemplate,下面就可以直接用了;JdbcTemplate 基本就可以满足一些日常需求了
关于事务
事务可分为两种,编程式事务和声明式事务;
编程式的我们都用过,比如 JDBC 中的 conn.setAutoCommite(false)
,或者 Hibernate 中的 session.beginTransaction()
;好处是操作比较灵活,能够实现细粒度的控制(但在 Spring 中一般不提倡使用);
声明式事务就是字面意思,先声明后面直接用,如果不需要细粒度的事务控制那么可以选择,在 Spring 中只需要在配置文件中配置一下就可以了,无侵入性、无耦合的,是基于 AOP 的;
下面主要说说声明式事务,基于 AOP 那也就可以得出只能对方法进行事务控制,对方法内的几行实现事务控制是做不到的,可以使用两种方式进行配置,XML 或者 注解;
XML配置方式
XML 的话这样配:
1 | <!-- 定义事务管理器(声明式的事务) --> |
除了上面列出的两种事务管理器,其实还有 JpaTransactionManager、JtaTransactionManager 等,就不介绍了,声明事务管理并不是这一种,更多的可以参考最后一个参考连接
分割线下的不设置也可以,大概……. ;这里的 txManager 就相当于是个切面了<tx:method>
设置:
属性 | 是否需要 | 默认值 | 描述 |
---|---|---|---|
name | 是 | 与事务属性关联的方法名。 | |
propagation | 不 | REQUIRED | 事务传播行为 |
isolation | 不 | DEFAULT | 事务隔离级别 |
timeout | 不 | -1 | 事务超时时间,以秒为单位 |
readonly | 不 | false | 事务是否只读 |
rollback-for | 不 | 将被触发回滚的Exception,以逗号隔开 | |
no-rollback-for | 不 | 不被触发回滚的Exception,以逗号隔开 |
注解方式
使用注解的方式还是要配下 XML 文件,起码要设置开启扫描、事务管理器之类的:
1 | <bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> |
然后就可以使用 @Transactional 注解进行设置了,关于这个注解前面文章中讲过(Spring 中的注解)
参考&资料
AOP 系列:https://my.oschina.net/itblog/blog/208067
https://jacksmiththu.github.io/2017/06/26/Spring%E4%B8%AD%E7%9A%84AOP/
https://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/index.html
http://www.cnblogs.com/hellojava/archive/2012/11/21/2780694.html
评论框加载失败,无法访问 Disqus
你可能需要魔法上网~~