面向切面编程 是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
利用AOP可以对业务逻辑的各个部分进行隔离,将那些与业务无关,却为业务模块所共同调用的逻辑 封装起来,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
事务管理、性能监视、权限控制、安全检查、缓存 、日志等
【1】JDK 本身的动态代理 Proxy 类; 【2】采用 cglib的enhancer增加类
JDK本身动态代理,要求必须提供 对应的接口
Cglib的增强可以不用任何接口
导入jar包
spring-aop-4.2.4.RELEASE.jar
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>4.3.10.RELEASEversion>
dependency>
编写目标类 及其对应的接口
IUserService 和 UserService
编写切面类
AspectObj
Spring容器进行相应配置
|
进行测试
//读取配置文件 |
语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
修饰符,一般省略
public 公共方法
* 任意
返回值,不能省略
void 返回没有值
String 返回值字符串
* 任意
包,[省略]
com.qf.crm 固定包
com.qf.crm.*.service crm包下面子包任意 (例如:com.qf.crm.service)
com.qf.crm.. crm包下面的所有子包(含自己)
com.qf.crm.*.service.. crm包下面任意子包,固定目录service,service目录任意包
类,[省略]
UserServiceImpl 指定类
*Impl 以Impl结尾
User* 以User开头
* 任意
方法名,不能省略
addUser 固定方法
add* 以add开头
*Do 以Do结尾
* 任意
(参数)
() 无参
(int) 一个整型
(int ,int) 两个
(..) 参数任意
throws ,可省略,一般不写。
案例:
execution**(public * com.qf.service.impl.*.*(..))**
匹配包或子包中的方法
pointcutexp包里的任意类: within(com.test.spring.aop.pointcutexp.*)
pointcutexp包和所有子包里的任意类:within(com.test.spring.aop.pointcutexp..*)
匹配实现接口的代理对象中的方法
用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
案例:实现了Intf接口的所有类,如果Intf不是接口,限定Intf单个类:this(com.test.spring.aop.pointcutexp.Intf)
当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型
匹配实现接口的目标对象中的方法
用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配
匹配参数格式符合标准的方法
参数为String类型(运行是决定)的方法: args(String)
对指定的bean所有的方法
用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
用于匹配所有持有指定注解类型内的方法;
带有@Transactional标注的所有类的任意方法:
@within(org.springframework.transaction.annotation.Transactional)
@target(org.springframework.transaction.annotation.Transactional)
用于匹配当前执行方法持有指定注解的方法;
带有@Transactional标注的任意方法:@annotation(org.springframework.transaction.annotation.Transactional) @within和@target针对类的注解,@annotation是针对方法的注解
用于匹配当前执行的方法传入的参数持有指定注解的执行;
参数带有@Transactional标注的方法:@args(org.springframework.transaction.annotation.Transactional)
该注解标注在参数上
before:前置通知(应用:各种校验、日志)
after:最终通知(应用:清理现场)
afterReturning:后置通知(应用:常规数据处理)
around:环绕通知(应用:十分强大,可以做任何事情)
afterThrowing:抛出异常通知(应用:包装异常信息)
UserService
切面类
AnnotationAspect
<context:component-scan base-package="com.aspect" />
<aop:aspectj-autoproxy />
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:Anno.xml")
public class TestAnno {
@Autowired
private IUserService user;
@Test
public void testAdvice(){
user.selectUser();
}
}
事务的隔离问题: 脏读 、不可重复读、幻读、可串行化
事务的传播属性:在两个业务之间如何共享事务
|
Jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=admin |
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}" />
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource" />
bean>
一个增加账户金额的;另外一个减少账户金额的
配置文件:增加jdbcTemplate的属性注入
<bean id="accountDaoImpl" class="com.hzqf.dao.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate" />
bean>
配置文件 : 增加 dao的属性注入
<bean id="accountService" class="com.hzqf.service.impl.AccountService" >
<property name="accountDao" ref="accountDaoImpl" />
bean>
增加事务管理器
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
配置业务方法的切面
<aop:config>
<aop:pointcut id="allMethods" expression="execution(* com.hzqf.service..*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="allMethods" />
aop:config>
配置业务管理中的方法及其对应的事务属性
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="transaction" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="select*" read-only="true"/>
tx:attributes>
tx:advice>
增加事务管理器
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
增加事务注解支持
<tx:annotation-driven transaction-manager="txManager" />
在需要增加事务管理的方法类上加上对应的@Transaction 注解
@Transactional //采用注解的方式进行事务控制
public void transaction(final String firstName, final String secondName, final int account) {
//第二个人扣款
userDao.accountOut(secondName,account);
//int i = 1 /0 ;
//第一个人收款
userDao.accountIn(firstName,account);
}