spring之AOP学习简单笔记

Aop概念

面向切面编程  是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

利用AOP可以对业务逻辑的各个部分进行隔离,将那些业务无关,却为业务模块所共同调用的逻辑 封装起来,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码

 

 

常见应用场景

事务管理、性能监视、权限控制、安全检查、缓存 、日志

Aop原理的动态代理实现【理解】

【1】JDK 本身的动态代理 Proxy 类; 【2】采用 cglib的enhancer增加类

 

JDK本身动态代理,要求必须提供 对应的接口

Cglib的增强可以不用任何接口

 

 

AOP的入门

导入jar包

spring-aop-4.2.4.RELEASE.jar 
<!--配置aop-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.10.RELEASE</version>
</dependency>

 

编写目标类 及其对应的接口

  IUserService 和  UserService 

编写切面类

  AspectObj 

Spring容器进行相应配置

<!-- new 目标类-->
<bean id="userService" class="com.hzqf.service.impl.UserService"/>
<bean id="prodcutService" class="com.hzqf.service.impl.UserService"/>
<!-- 切面类 -->
<bean id="aspect" class="com.hzqf.aspect.AspectObj"/>

<aop:config>
    <!-- 定义切面类 -->
   <!-- <aop:pointcut id="point" expression="* com.hzqf.service..*.*(..) "/>-->
    <aop:aspect ref="aspect">
        <!-- 切入点表达式 -->
        <aop:pointcut id="pointCut" expression="execution(* com.hzqf.service..*.*(..))"/>
        <!-- 切面类里的 通知类型1:前置通知-->
        <aop:before method="beforeMethod" pointcut-ref="pointCut" />
        <!--通知类型2:最终通知-->
        <aop:after method="afterMethod" pointcut-ref="pointCut" />
       <!-- 通知类型3: 后置通知-->
        <aop:after-returning method="afterReturningMethod" pointcut-ref="pointCut"/>
        <!--通知类型4: 异常通知-->
        <aop:after-throwing method="throwingMethod" pointcut-ref="pointCut" />
        <!--通知类型5: 环绕通知-->
        <aop:around method="aroundMethod" pointcut-ref="pointCut" />
    </aop:aspect>

</aop:config>

 

进行测试

//读取配置文件
 ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
 IUserService userService =  (IUserService) ac.getBean("userService");
 //userService.insertUser("风味");
 userService.selectUser();

 

切入点表达式

execution() 

语法: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.*.*(..))**

 

within:

匹配包或子包中的方法

pointcutexp包里的任意类: within(com.test.spring.aop.pointcutexp.*)

pointcutexp包和所有子包里的任意类:within(com.test.spring.aop.pointcutexp..*)

 

this:

匹配实现接口的代理对象中的方法

用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;

案例:实现了Intf接口的所有类,如果Intf不是接口,限定Intf单个类:this(com.test.spring.aop.pointcutexp.Intf)

当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型

target:

匹配实现接口的目标对象中的方法

用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配

args:

匹配参数格式符合标准的方法

参数为String类型(运行是决定)的方法: args(String)

bean(id) 

对指定的bean所有的方法

@target:

用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;

@within:

用于匹配所有持有指定注解类型内的方法;

带有@Transactional标注的所有类的任意方法:

@within(org.springframework.transaction.annotation.Transactional)

@target(org.springframework.transaction.annotation.Transactional)

 

@annotation:

用于匹配当前执行方法持有指定注解的方法;

带有@Transactional标注的任意方法:@annotation(org.springframework.transaction.annotation.Transactional) @within和@target针对类的注解,@annotation是针对方法的注解

 

@args:

用于匹配当前执行的方法传入的参数持有指定注解的执行;

参数带有@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();
    }
}

SpringAOP的事务

事务的隔离问题: 脏读 、不可重复读、幻读、可串行化

事务的传播属性:在两个业务之间如何共享事务

 

案例 : 相互转账问题

增加相应的事务jar包

 

 

<!-- 数据库连接jar-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.10.RELEASE</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.45</version>
</dependency>

<!-- 事务 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>4.3.10.RELEASE</version>
</dependency>

 

配置数据库jdbc 连接

   Jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/mybatis

jdbc.username=root

jdbc.password=admin

配置数据源 dataSources

<!--读取 jdbc.properties-->
<context:property-placeholder location="classpath:jdbc.properties" />

<!--springJDBC: 数据库连接-->

<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>

增加spring的jdbc操作

<!-- 采用spring 自身的 jdbc解决方案 : 后续用 mybatis的解决方案 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
    <property name="dataSource" ref="dataSource" />
</bean>

在dao中实现数据库的两个操作:

一个增加账户金额的;另外一个减少账户金额的

配置文件:增加jdbcTemplate的属性注入

<bean id="accountDaoImpl" class="com.hzqf.dao.AccountDaoImpl">
    <property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>

 

在service中调用dao的操作。并完成 转账业务

配置文件 : 增加 dao的属性注入

<bean id="accountService" class="com.hzqf.service.impl.AccountService" >
    <property name="accountDao" ref="accountDaoImpl" />
  </bean>

 

事务管理配置步骤:

增加事务管理器

<!-- 1.增加事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

配置业务方法的切面

<!-- 2.配置所有需要被事务管理器管理的 目标类及其方法-->
<aop:config>
    <!-- 哪些类的哪些方法参与事务 -->
    <aop:pointcut id="allMethods" expression="execution(* com.hzqf.service..*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="allMethods" />
</aop:config>

配置业务管理中的方法及其对应的事务属性

<!--3.沿用事务管理器,来管理 需要进行事务操作的各种方法-->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <!--事务属性主要配置方案:
        isolation: 表示事务隔离级别: 取值 default
        propagation:表示事务的传播级别:取值 REQUIRED
        no-rollback-for:表示就算有里面的异常也不进行回滚;
        rollback-for:表示有里面的异常就需要回滚;
        timeout: 执行超时时间; 秒级别
        read-only:是否只读
        -->
        <!--转账业务-->
        <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>

 

 

采用注解的方式:

增加事务管理器

<!-- 1.增加事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

增加事务注解支持

<!-- 开启注解功能的 事务管理; 后续,只要在对应需要处理业务的方法上,增加 @Transaction注解 即可-->
 <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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值