spring的aop实现与自定义Advisor

spring的aop实现与自定义Advisor,第1张

>1、什么是AOP

AOP(Aspect Orient Programming) : 面向切面编程

Aspect :表示切面, 给业务方法增加的功能,叫做切面。 切面一般都是非业务功能, 而且切面功能一般都是可以复用的。 例如 日志功能, 事务功能, 权限检查,参数检查, 统计信息等等。

Orient:面向,对着

Programming:编程。

2、 怎么理解面向切面编程 ? 以切面为核心设计开发你的应用。

1)设计项目时, 找出切面的功能。

2)安排切面的执行时间, 执行的位置。
3、AOP的作用:

1)让切面功能复用

2)让开发人员专注业务逻辑。 提高开发效率

3)实现业务功能和其他非业务功能解耦合。

4)给存在的业务方法, 增加功能,不用修改原来的代码

4、AOP中术语

1)Aspect:切面, 给业务方法增加的功能。

2)JoinPoint:连接点, 连接切面的业务方法。 在这个业务方法执行时,会同时执行切面的功能。

3)Pointcut: 切入点, 是一个或多个连接点集合。 表示这些方法执行时,都能增加切面的功能。

表示切面执行的位置。

4)target: 目标对象, 给那个对象增加切面的功能, 这个对象就是目标对象。

5)Advice:通知(增强),表示切面的执行时间。 在目标方法之前执行切面,还是目标方法之后执行切面。

AOP中重要的三个要素: Aspect, Pointcut , Advice 这个概念的理解是: 在Advice的时间,在Pointcut的位置, 执行Aspect

AOP是一个动态的思想。 在程序运行期间,创建代理(ServcieProxy),使用代理执行方法时,增加切面的功能。这个代理对象是存在内存中的。

5、什么时候你想用AOP

你要给某些方法 增加相同的一些功能。 源代码不能改。 给业务方法增加非业务功能,也可以使用AOP

6、AOP技术思想的实现

使用框架实现AOP。 实现AOP的框架有很多。 有名的两个

1) Spring : Spring框架实现AOP思想中的部分功能。 Spring框架实现AOP的 *** 作比较繁琐,比重。

2) Aspectj : 独立的框架,专门是AOP。 属于Eclipse
7、通知

Aspectj表示切面执行时间,用的通知(Advice)。 这个通知可以使用注解表示。

讲5个注解, 表示切面的5个执行时间, 这些注解叫做通知注解。

@Before : 前置通知

@AfterRetunring: 后置通知

@Around: 环绕通知

@AfterThrowing:异常通知

@After:最终通知
8、Pointcut 位置

Pointcut 用来表示切面执行的位置, 使用Aspectj中切入点表达式。

你好,别想的太难了,你可以参考一下底下:
1、使用基于注解的AOP事务管理
探索tx:annotation-driven标签:
标签是注解驱动的事务管理支持的核心。
标签的属性:
transaction-manager:指定到现有的PlatformTransactionManager bean的引用,通知会使用该引用。default="transactionManager"
mode:指定Spring事务管理框架创建通知bean的方式。可用的值有proxy和aspectj。前者是默认值,表示通知对象是个JDK代理;后者表示Spring AOP会使用AspectJ创建代理。
order:指定创建的切面的顺序。只要目标对象有多个通知就可以使用该属性。
proxy-target-class:该属性如果为true就表示你想要代理目标类而不是bean所实现的所有接口。default="false"
探索@Transactional注解:
你可以指定传播、隔离级别、超时以及允许和不允许的异常。
@Transactional注解的属性:
propagation:指定事务定义中使用的传播
isolation:设定事务的隔离级别
timeout:指定事务的超市(秒)
readOnly:指定事务的超时
noRollbackFor:目标方法可抛出的异常所构成的数组,但通知仍会提交事务
rollbackFor:异常所构成的数组,如果目标方法抛出了这些异常,通知就会回滚事务
基于注解的事务管理小结:
如果定义在类上,那么所有的方法都使用相同的方式,有些read就会抱怨给太多的东西了。
如果在每个方法上都定义注解,那么就会很麻烦。
(可以使用XML AOP事务管理能更好的处理这种情况)
2、使用XML AOP事务管理
标签,该标签会创建一个事务处理通知。
view plaincopy to clipboardprint

<aop:pointcut id="allServiceMethods"
expression="execution( comapressprospring2ch16services())"/>
<aop:advisor advice-ref="defaultTransactionAdvice"
pointcut-ref="allServiceMethods"/>
<tx:method
name=""
isolation="DEFAULT"
propagation="REQUIRED"
no-rollback-for="javalangRuntimeException"
timeout="100"/>
<tx:method
name="get"
read-only="true"/>
3、tx:advice标签简介
id是该advice bean的标识,而transaction-manager则必须引用一个PlatformTransactionManager bean。
还可以通过标签定制标签所创建的通知的行为。
标签的属性:
name:方法名的匹配模式,通知根据该模式寻找匹配的方法。
propagation:设定事务定义所用的传播级别。
isolation:设置事务的隔离级别。
timeout:指定事务的超时(秒)。
read-only:该属性为true指示事务是只读的
no-rollback-for:以逗号分隔的异常类的列表,目标方法可以跑出这些异常而不会导致通知执行回滚
rollback-for:以逗号分隔的异常类的列表,当目标方法跑出这些异常时会导致通知执行回滚。默认情况下,该列表为空,因此不在no-rollback-for列表中的任何运行时异常都会导致回滚。
中isolation(隔离)和propagation(传播)参数的含义:
getIsolationLevel:他对其他事务所看到的数据变化进行控制。
事务隔离级别:
隔离级别 说明
ISOLATION_DEFAULT 默认级别(对大多数数据库来说就是ISOLATION_READ_COMMITTED)
ISOLATION_READ_UNCOMMITTED 最低的隔离级别。事实上我们不应该隔离级别,因为在事务完成前,其他事务可以看到该事务所修改的数据。而在其他事务提交前,该事务也可以看到其他事务所做的修改。
ISOLATION_READ_COMMITTED 大多数数据库的默认级别。在事务完成前,其他事务无法看到该事务所修改的数据。遗憾的是,在该事务提交后,你就可以查看其他事务插入活更新的数据。这意味着在事务的不同点上,如果其他事务修改数据,你会看到不同的数据。
ISOLATION_REPEATABLE_READ 该隔离级别确保如果在事务中查询了某个数据集,你至少还能再次查询到相同的数据集,即使其他事务修改了所查询的数据。然而如果其他事务插入了新数据,你就可以查询到该新插入的数据。
ISOLATION_SERIALIZABLE 代价最大、可靠性最高的隔离级别,所有的事务都是俺顺序一个接一个的执行。
getPropagationBehavior:指定了当代码请求一个新的事务时Spring所做的事情。
传播行为指:
传播行为 说明
PROPAGATION_REQUIRED 当前如果有事务,Spring就会使用该事务;否则会开始一个新事务。
PROPAGATION_SUPPORTS 当前如果有事务,Spring就会使用该事务;否则不会开启一个新事务。
PROPAGATION_MANDATORY 当前如果有事务,Spring就会使用该事务;否则会抛出异常。
PROPAGATION_REQUIRES_NEW Spring总会开始一个新事务。如果当前有事务,则该事务挂起。
PROPAGATION_NOT_SUPPORTED Spring不会执行事务中的代码。代码总是在非事务环境下执行,如果当期有事务,则该事务挂起。
PROPAGATION_NEVER 即使当前有事务,Spring也会在飞事务环境下执行。如果当前有事务,则抛出异常。
PROPAGATION_NESTED 如果当前有事务,则在嵌套事务中执行。如果没有,那么执行情况与PROPAGATION_REQUIRED一样。
望采纳!

1、@Transactional使用位置

Ⅰ 写在接口类上,该接口的所有实现类的所有方法都会有事务;
Ⅱ 写在接口方法上,该接口的所有实现类的该方法都会有事务;

Ⅰ 写在实现类上,该类中的所有方法都会有事务;
Ⅱ 写在实现类方法上,该方法上有事务。

建议:写在实现类或实现类的方法上。

2、PlatformTransactionManager

PlatformTransactionManager是Spring中的事务管理接口,具体如下:

3、DataSourceTransactionManager

Spring中JDBC事务管理实现类是DataSourceTransactionManager,所以我们使用MyBatis时,如果需要进行事务管理则配置该事务管理即可。

1、基础准备

jdbcproperties如下:

JdbcConfig如下:

2、测试

1、相关注解

配置类注解,定义在配置类上。
设置当前Spring环境中开启注解式事务支持。

接口、类、方法注解,定义在接口、类、方法上。
为当前业务层方法添加事务(如果设置在类或接口上方则类或接口中所有方法均添加事务)。

2、事务角色

发起事务方,在Spring中通常指代业务层开启事务的方法。

加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法。

3、@Transactional常用属性

true只读事务,false读写事务,增删改要设为false,查询设为true。

设置超时时间单位秒,在多长时间之内事务没有提交成功就自动回滚,-1表示不设置超时时间。

当出现指定异常进行事务回滚。

4、事务传播行为

比如上述测试案例中,我们给log方法上的@Transactional设置了传播属性为REQUIRES_NEW,表示当前事务协调员会自己开启一个事务。并不会因为transfer发生回滚而回滚。

Ⅰ REQUIRED(默认);
Ⅱ SUPPORTS;
Ⅲ MANDATORY;
Ⅳ REQUIRES_NEW;
Ⅴ NOT_SUPPORTED;
Ⅵ NEVER;
Ⅶ NESTED。

以上即为Spring AOP-事务管理的全部内容,感谢阅读。

AOP配置,@EnableAspectJAutoProxy,@Before,@After,@AfterReturning,@AfterThrowing
AOP:动态代理
指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;
1导入aop模块;Spring AOP:
<dependency>
<groupId>orgspringframeworkboot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2定义一个业务逻辑类(CalculateController);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
3定义一个日志切面类(LogAop):切面类里面的方法需要动态感知CalculateControllercalculateNum运行到哪里然后执行;
通知方法:
前置通知(@Before):logStart:在目标方法(calculateNum)运行之前运行
后置通知(@After):logEnd:在目标方法(calculateNum)运行结束之后运行(无论方法正常结束还是异常结束)
返回通知(@AfterReturning):logReturn:在目标方法(calculateNum)正常返回之后运行
异常通知(@AfterThrowing):logException:在目标方法(calculateNum)出现异常以后运行
环绕通知(@Around):动态代理,手动推进目标方法运行(joinPointprocced())
4给切面类的目标方法标注何时何地运行(通知注解);
5将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
6必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
7给配置类中加 @EnableAspectJAutoProxy 开启基于注解的aop模式
在Spring中很多的 @EnableXXX;
三步:
1)将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)
2)在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
3)开启基于注解的aop模式;@EnableAspectJAutoProxy
配置
// @EnableAspectJAutoProxy 开启基于注解的aop模式
@EnableAspectJAutoProxy
@Configuration
public class MyAopConfig {
@Bean
public CalculateController calculateController(){
return new CalculateController();
}
@Bean
public LogAop logAop(){
return new LogAop();
}
}
/
切面类
/
// @Aspect: 告诉Spring当前类是一个切面类
@Aspect
public class LogAop {
//抽取公共的切入点表达式
//1、本类引用
//2、其他的切面引用
@Pointcut("execution(public int comexamplestudyworkworkcontrollerCalculateController())")
public void pointCut(){};
@Before(value ="pointCut()")
public void logStart(JoinPoint joinPoint){
Systemoutprintln(joinPointgetSignature()getName()+"方法运行前。。。参数列表是:{"+ ArraysasList(joinPointgetArgs())+"}");
}
// 外部切面类引用可以用全类名
@After("comexamplestudyworkworkaopLogAoppointCut()")
public void logEnd(JoinPoint joinPoint){
Systemoutprintln(joinPointgetSignature()getName()+"方法结束。。。");
}
//JoinPoint一定要出现在参数表的第一位
@AfterReturning(value = "pointCut()",returning = "obj")
public void logReturn(JoinPoint joinPoint,Object obj){
Systemoutprintln(joinPointgetSignature()getName()+"方法正常返回。。。运行结果是:{"+obj+"}");
}
@AfterThrowing(value = "pointCut()",throwing = "e")
public void logxception(JoinPoint joinPoint,Exception e){
Systemoutprintln(joinPointgetSignature()getName()+"方法异常返回。。。异常结果是:{"+e+"}");
}
}
// 业务
public class CalculateController {
public int calculateNum(int i, int j){
Systemoutprintln("CalculateController类的calculateNum方法正在运行");
return i/j;
}
}
输出
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyAopConfigclass);
CalculateController bean = applicationContextgetBean(CalculateControllerclass);
beancalculateNum(1,1);
}
输出结果
异常输出
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyAopConfigclass);
CalculateController bean = applicationContextgetBean(CalculateControllerclass);
beancalculateNum(1,0);
}
输出结果
 


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/13395007.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-07-28
下一篇 2023-07-28

发表评论

登录后才能评论

评论列表(0条)

保存