Spring基础学习笔记(二)

Spring(AOP)

1、AOP:

1.1、 中文名称:面向切面编程
1.2、英文名称:(Aspect Oriented Programming)

2、什么是面向切面编程(AOP)?

2.1、在程序原有纵向执行流程中,针对某一个或某一些方法添加通
知,形成横切面过程就叫做面向切面编程.
2.2、画图示意:

在这里插入图片描述
2.3、说明:
正常程序执行流程都是纵向执行的流程,面向切面编程则是在原有的纵向执行流程中添加横向切面的流程而且不需要修改原有程序代码,因此它具有高扩展性(意味着原有功能相当于释放了部分逻辑,让各个模块(或者说方法)职责更加明确)。

3、AOP常用概念:

3.1、原有功能: 即切点(pointcut)。
3.2、前置通知: 在切点之前执行的功能(before advice)。
3.3、后置通知: 在切点之后执行的功能(after advice)。
3.4、异常通知:在切点执行过程中出现异常时触发。
3.5、环绕通知:前置和后置写在一个通知中。
3.6、切面:所有功能总称。
3.7、织入: 把切面嵌入到原有功能的过程。

4、Spring实现AOP的两种方式

4.1、Schema-based方式

4.1.1、导入所需jar包(Maven添加依赖):
在这里插入图片描述
4.1.2、新建通知类:
4.1.2.1、新建前置通知类:
参数说明:
arg0: 切点方法对象Method 对象
arg1: 切点方法参数
arg2:切点在哪个对象中

public class MyBeforeAdvice implements
MethodBeforeAdvice {
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("执行前置通知");
}
}

4.1.2.2、新建后置通知类:
参数说明:
arg0: 切点方法返回值
arg1:切点方法对象
arg2:切点方法参数
arg3:切点方法所在类的对象

public class MyAfterAdvice implements
AfterReturningAdvice {
@Override
public void afterReturning(Object arg0, Method arg1,
Object[] arg2, Object arg3) throws Throwable {
System.out.println("执行后置通知");
}
}

4.1.3、配置spring 配置文件
4.1.3.1、引入aop 命名空间
4.1.3.2、配置通知类的
4.1.3.3、配置切面

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/sc
hema/beans
http://www.springframework.org/schema/beans/spring-be
ans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.
xsd">
<!-- 配置通知类对象,在切面中引入-->
<bean id="mybefore"
class="com.myhexin.advice.MyBeforeAdvice"></bean>
<bean id="myafter"
class="com.myhexin.advice.MyAfterAdvice"></bean>
<!-- 配置切面-->
<aop:config>
<!-- 配置切点-->
<aop:pointcut expression="execution(*
com.myhexin.test.Demo.demo2())" id="mypoint"/>
<!-- 通知-->
<aop:advisor advice-ref="mybefore"
pointcut-ref="mypoint"/>
<aop:advisor advice-ref="myafter"
pointcut-ref="mypoint"/>
</aop:config>
<!-- 配置Demo 类,测试使用-->
<bean id="demo" class="com.myhexin.test.Demo"></bean>
</beans>

4.1.4、编写测试代码

public class Test {
public static void main(String[] args) {
ApplicationContext ac = new
ClassPathXmlApplicationContext("applicationContext.xm
l");
Demo demo = ac.getBean("demo",Demo.class);
demo.demo1();
demo.demo2();
demo.demo3();
}
}

4.1.5、结果:
在这里插入图片描述

4.2、AspectJ方式

4.2.1、新建通知类,不用实现(类中方法名任意)

public class MyAdvice {
public void mybefore(){
System.out.println("执行前置通知" );
}
public void myafter(){
System.out.println("执行后置通知");
}
}

4.2.2、配置spring配置文件

<aop:config>
<aop:aspect ref="myadvice">
<aop:pointcut expression="execution(*
com.myhexin.test.Demo.demo1())" id="mypoint"/>
<aop:before method="mybefore"
pointcut-ref="mypoint"/>
<aop:after method="myafter"
pointcut-ref="mypoint"/>
</aop:aspect>
</aop:config>

4.2.3、编写测试类

public class Test {
public static void main(String[] args) {
ApplicationContext ac = new
ClassPathXmlApplicationContext("applicationContext.xm
l");
Demo demo = ac.getBean("demo",Demo.class);
demo.demo1();
demo.demo2();
demo.demo3();
}
}

4.2.4、结果:
在这里插入图片描述

5、异常通知

5.1、异常通知配置(Aspect方式)

5.1.1、说明:只有当切点报异常时才能触发异常通知,要是切点的异常直接被自己处理掉了那么也不能触发异常通知。
5.1.2、spring中只有Aspect方式提供了异常通知的办法,若想通过schema-based方式实现则需要按照特定的要求自己编写方法进行实现。
5.1.3、新建异常通知类,在类中写一个任意名称的方法:

public class MyThrowAdvice{
public void myexception(Exception e1){
System.out.println("执行异常通知
"+e1.getMessage());
}
}

5.1.4、在spring 配置文件中进行配置
5.1.4.1、说明:
<aop:aspect>的ref 属性表示:方法在哪个类中.
<aop: xxxx/> 表示什么通知
method: 当触发这个通知时,调用哪个方法
throwing: 异常对象名,必须和通知中方法参数名相同(可
以不在通知中声明异常对象)

<bean id="mythrow"
class="com.myhexin.advice.MyThrowAdvice"></bean>
<aop:config>
<aop:aspect ref="mythrow">
<aop:pointcut expression="execution(*
com.bjsxt.test.Demo.demo1())" id="mypoint"/>
<aop:after-throwing method="myexception"
pointcut-ref="mypoint" throwing="e1"/>
</aop:aspect>
</aop:config>
<bean id="demo" class="com.myhexin.test.Demo"></bean>
5.2、异常通知配置(Schema-based 方式)

5.2.1、新建一个类实现throwsAdvice接口
5.2.2、必须自己写方法并且方法名必须叫afterThrowing
5.2.3、有两种参数方式:
5.2.3.1、参数必须是1个或者4个的
5.2.3.2、异常类型要与切点报的异常类型一致的(可以用Exception来接)
5.2.4、代码:

public class MyThrow implements ThrowsAdvice{
// public void afterThrowing(Method m, Object[] args,
Object target, Exception ex) {
// System.out.println("执行异常通知");
// }
public void afterThrowing(Exception ex) throws
Throwable {
System.out.println("执行异常通过-schema-base 方式
");
}
}

5.2.5、在xml中的配置:

<bean id="mythrow"
class="com.myhexin.advice.MyThrow"></bean>
<aop:config>
<aop:pointcut expression="execution(*
com.myhexin.test.Demo.demo1())" id="mypoint"/>
<aop:advisor advice-ref="mythrow"
pointcut-ref="mypoint" />
</aop:config>
<bean id="demo" class="com.myhexin.test.Demo"></bean>

6、环绕通知

6.1、通过Schema-based方式

6.1.1、新建一个类实现MethodInterceptor

public class MyArround implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation arg0) throws
Throwable {
System.out.println("环绕-前置");
Object result = arg0.proceed();//放行,调用切点方式
System.out.println("环绕-后置");
return result;
}
}

6.1.2、配置xml:

<bean id="myarround"
class="com.myhexin.advice.MyArround"></bean>
<aop:config>
<aop:pointcut expression="execution(*
com.myhexin.test.Demo.demo1())" id="mypoint"/>
<aop:advisor advice-ref="myarround"
pointcut-ref="mypoint" />
</aop:config>
<bean id="demo" class="com.myhexin.test.Demo"></bean>
6.2、通过AspectJ方式

6.2.1、新建类(随意取名、不用实现任何借口)

public class MyAdvice {
public Object myarround(ProceedingJoinPoint p) throws
Throwable{
System.out.println("执行环绕");
System.out.println("环绕-前置");
Object result = p.proceed();
System.out.println("环绕后置");
return result;
}

6.2.2、配置spring配置文件(这里展示所有的通知,为了说明每个标签的含义):
说明:其中有两个切点(可以有带参数也可以不带参数)。
6.2.2.1、execution() 括号不能扩上args,中间使用and 不能使用&& 由spring 把and 解析成&&。
6.2.2.2、args(名称) 名称自定义的.顺序和demo1(参数,参数)要对应。
6.2.2.3、<aop:before/> arg-names=” 名称” 名称来源于
expression=”” 中args(),并且名称必须一样。
6.2.2.4、args() 有几个参数,arg-names 里面也必须有几个参数。
6.2.2.5、arg-names=”” 里面名称必须和通知方法参数名对应。

6.2.2.6、<aop:after/>与<aop:after-returing/>的区别:
两个都是后置通知,但<aop:after/>是否出现异常都会执行,个人理解跟(finally差不多),而<aop:after-returing/>只有当切点正确执行时
执行。
6.2.2.7、<aop:after/> 和<aop:after-returing/> 和
<aop:after-throwing/>执行顺序和配置顺序有关,在配置文件中哪个写在前面就先执行哪一个的。

<aop:config>
<aop:aspect ref="myadvice">
<aop:pointcut expression="execution(*
com.myhexin.test.Demo.demo1(String,int)) and
args(name1,age1)" id="mypoint"/>
<aop:pointcut expression="execution(*
com.myhexin.test.Demo.demo1(String)) and args(name1)"
id="mypoint1"/>
<!--<aop:before method="mybefore"
pointcut-ref="mypoint" arg-names="name1,age1"/>
<aop:before method="mybefore1"
pointcut-ref="mypoint1" arg-names="name1"/>
 <aop:after method="myafter"
pointcut-ref="mypoint"/>
<aop:after-returning method="myaftering"
pointcut-ref="mypoint"/>
<aop:after-throwing method="mythrow"
pointcut-ref="mypoint"/>-->
<aop:around method="myarround"
pointcut-ref="mypoint"/>
</aop:aspect>
</aop:config>

7、使用注解(主要基于Aspect方式进行的)

7.1、前提工作:

7.1.1、由于spring 不会自动去寻找注解,所以必须告诉spring 哪些包下的类中可能
有注解。
7.1.2、在此就使用context中的component-scan进行包的扫描

<context:component-scan
base-package="com.myhexin.advice"></context:component-s
7.2、@Component介绍

7.2.1、@Component相当于
7.2.2、如果没有参数(不填),则把类名首字母变小写来使用,相当于
7.2.3、@Component(“自定义名称”) 可以自定义取名称。

7.3、实现步骤:

7.3.1、首先把用到的包都进扫描进来:

<context:component-scan
base-package="com.myhexin.advice,com.myhexin.test"></cont
ext:component-scan>

7.3.2、然后在Demo类中加@Component注解,在切点方法上加@Pointcut(“”)来定义切点

@Component
public class Demo {
@Pointcut("execution(*
com.myhexin.test.Demo.demo1())")
public void demo1() throws Exception{
// int i = 5/0;
System.out.println("demo1");
}
}

7.3.3、在通知类中进行配置:
7.3.3.1、加上@Component 类从而使通知类能被spring 管理。
7.3.3.2、加上@Aspect 相当于<aop:aspect/>表示通知方法在当前类中。

@Component
@Aspect
public class MyAdvice {
@Before("com.myhexin.test.Demo.demo1()")
public void mybefore(){
System.out.println("前置");
}
@After("com.myhexin.test.Demo.demo1()")
public void myafter(){
System.out.println("后置通知");
}
@AfterThrowing("com.myhexin.test.Demo.demo1()")
public void mythrow(){
System.out.println("异常通知");
}
@Around("com.myhexin.test.Demo.demo1()")
public Object myarround(ProceedingJoinPoint p) throws
Throwable{
System.out.println("环绕-前置");
Object result = p.proceed();
System.out.println("环绕-后置");
return result;
}
}
7.4、注解总结

使用注解的方式实现AOP不用复杂的配置xml,其本质其实就是将xml中的配置方式替换成@XXX的这种方式进行。

8、总结

Spring的面向切面编程很好的将原本纵向执行的程序从横向进行插入功能,针对某些原有的功能使之释放了部分逻辑,然后由其他的方法帮助其完成这部分逻辑,使整个方法的职责更加明确,更加简洁。这也从另一个方面提高了代码的高可扩展性,并且真正的达到了不用修改原有程序的一丁点代码,这也许才是真正的高扩展性的体现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值