目录
- 回顾
- 使用SpringIOC的项目开发流程
- SpringAOP的介绍
- 问题:
- 解决:
- 实现:
- SpringAOP的SchemaBase方式实现
- SchemaBase方式实现的基本流程
- 步骤
- SpringAOP的专业概念:
- SchemaBase方式环绕通知方式实现AOP
- 解释:
- 实现:
- 特点:
- 使用:
- SchemaBase方式的异常通知
- 问题:
- 解决:
- 使用:
- SpringAOP的SchemaBase方法的参数
- 前置通知
- [2]后置通知
- [3]环绕通知
- [4]异常通知
回顾
使用SpringIOC的项目开发流程
①创建一个web项目 ②导入相关jar包(SpringIOC Mybatis 整合包 jdbc) ③在src下创建MVC的包结构 ④在src下创建并配置applicationcontext.xml文件 配置数据源bean 配置工 厂bean 配置mapper扫描bean 配置业务层bean(注入mapper对象) ⑤在web.xml中配置applicationcontext.xml的路径和Spring 的监听器. ⑥完成功能开发
SpringAOP的介绍
问题:
①假如我们有当前功能方法的源码,就需要阅读当前方法的源码,然后再增加自己的新的逻辑代码.并且修改好后,需要将新的类文件替换旧的类文件,而阅读代码本身效率极低. ②假如我们没有源码文件,那么就无法直接修改源码增加新的功能逻辑,怎么 办?
解决:
在不修改原有功能逻辑的基础上完成功能扩展.
实现:
SpringAOP
spring AOP就是为了功能的扩展。 现在有一个方法,需要对它进行功能的扩展,我们需要使用spring AOP 进行功能的扩展 spring AOP 就是动态的生成一个扩展后的方法
我们需要给spring AOP 原来的方法 ,需要扩展的方法,都给了springAOP之后 他会自动的整合为一个扩展后的方法对象,并且返回给你,
所以,我们通过spring AOP之后,拿到的就是功能扩展之后的代码。
SpringAOP的SchemaBase方式实现
SchemaBase方式实现的基本流程
SpringAOP的本质总结: 我们将要进行功能扩展相关的材料以及对应的组织规则告诉Spring容器,Spring容器帮我们动态创建一个代理对象。我们直接从Spring容器中获取代理对象完成功能开发。
也就是我们把我们自己写的功能扩展的类写在容器里面,在容器里面进行组装,返回一个代理对象,那么这个代理对象里面就会有我们重新写的方法
步骤
①导入SpringAOP的jar包
②在src下创建包advice,并创建前置通知类和后置通知类 前置通知类 创建一个普通的java类,实现MethodBeforeAdvice接口, 重写before方法,在before方法中声明扩展前的逻辑代码。
代码语言:javascript复制 1、前置通知:
public class BaseBeforeAdvice implements MethodBeforeAdvice {
// method : 切入的方法 <br>
//args :切入方法的参数 <br>
// target :目标对象
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("===========进入beforeAdvice()============ n");
System.out.print("准备在" target "对象上用");
System.out.print(method "方法进行对 '");
System.out.print(args[0] "'进行删除!nn");
System.out.println("要进入切入点方法了 n");
}
}
方法名:before 调用者:代理对象中的扩展方法调用 方法体:声明切点之前执行的扩展代码 参数: Method method, 这个就是要扩展功能的方法 Object[] objects, 这个就是方法参数的组 Object o 这个就是原来的类对象
后置通知类: 创建一个普通的Java类,实现AfterReturningAdvice接 口,重写after方法,并在after方法中声明扩展后的逻 辑代码。
代码语言:javascript复制public class BaseAfterReturnAdvice implements AfterReturningAdvice {
//returnValue :切入点执行完方法的返回值,但不能修改 <br>
// method :切入点方法 <br>
// args :切入点方法的参数数组 <br>
// target :目标对象
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("==========进入afterReturning()=========== n");
System.out.println("切入点方法执行完了 n");
System.out.print(args[0] "在");
System.out.print(target "对象上被");
System.out.print(method "方法删除了");
System.out.print("只留下:" returnValue "nn");
}
}
方法名:after 调用者:代理对象中的扩展方法调用 方法体:声明切点之后执行的扩展代码 参数: Object o, Method method, Object[] objects, Object o1
======================================= 比前置通知里面的方法的参数多一个 多的一个参数是 切点方法的返回值
③在applicationcontext.xml文件中配置资源的bean对象以及声明组装规则。 资源对象: 要进行功能扩展的bean对象 前置通知的bean对象 后置通知的bean对象 声明组装规则:(使用AOP标签完成) 声明切点 声明组装
④从Spring容器中直接获取代理对象完成功能开发
注意:如果让Spring容器对象某个bean对象按照AOP进行功能扩展,则从Spring容器中使用该对象的ID获取的对象已经不是其本身了,而是他的代理对象(夺舍)
============================================
首先我们先创建我们要扩展的类
之后设置扩展的方法
在xml里面进行配置 配置扩展组装规则的标签是需要一个新的,所以我们要导入之后,才可以使用组装的标签,在头文件里面进行导入 导入之后就可以使用 aop:config标签了
代码语言:javascript复制 <!--配置A对象的bean-->
<bean id="a" class="com.pojoAop.TestA"></bean>
<!--配置扩展前的bean-->
<bean id="before" class="com.adviceAop.MyBefore"></bean>
<!--配置扩展后的bean-->
<bean id="after" class="com.adviceAop.MyAfter"></bean>
<!--配置扩展组装规则-->
<aop:config>
<!--指明要进行功能扩展的方法-->
<aop:pointcut id="mp" expression="execution(* com.pojoAop.TestA.testA())"/>
<!--组件-->
<aop:advisor advice-ref="before" pointcut-ref="mp"></aop:advisor>
<aop:advisor advice-ref="after" pointcut-ref="mp"></aop:advisor>
</aop:config>
SpringAOP的专业概念:
真实对象要进行功能扩展的对象,相当于A对象 代理对象完成功能扩展的对象,相当于B对象. 切点要进行功能扩展的方法,相当于testA()方法 前置通知方法:在切点之前执行的扩展方法 后置通知方法在切点之后执行的扩展方法 切面:由前置通知 切点 后置通知形成的横向执行的面 织入:由前置通知 切点 后置通知形成切面的过程 AOP的概念:面向切面的编程
SchemaBase方式环绕通知方式实现AOP
解释:
前面我们已经使用前置通知方式和后置通知方式完成了AOP的扩展代码的编写。而我们之前学过过滤器的概念,在过滤器中会先执行一部分代码,执行后如果放行了则继续执行 Servlet,Servlet执行后再次回到过滤器中执行。那么,从AOP的角度过滤器就相当于Servlet的扩展对象了。过滤器中的拦截方法,就相当于扩展方法,而我们将扩展代码和调用原有切点方法的代码全部直接声明在一个方法中了,那么能不能采用此种方案来完成我们会自己的AOP扩展呢?
实现:
环绕通知
特点:
将扩展代码和调用原有切点方法的代码声明在一起,简化扩展流程。也就说环绕通知中包含了前置通知和后置通知。
使用:
①创建一个普通Java类,实现环绕通知的接口。
代码语言:javascript复制public class MyRound implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
//扩展前代码
System.out.println("环绕通知---前");
//调用原有代码--放行
Object proceed = methodInvocation.proceed();
//扩展后代码
System.out.println("环绕通知---后:" proceed);
return proceed;
}
}
方法名:invoke 调用者:代理对象中的扩展方法调用 方法体:声明扩展代码同时根据需求是否放行。 参数: MethodInvocation methodInvocation
原来方法的参数,名字,也就是前置通知参数那些概念,现在是整合到一个参数里面methodInvocation,这个参数里面有很多的其他的方法,可以得到前置通知参数一样的效果。
②在applicationcontext.xml文件中配置环绕通知的bean
③在组装规则中使用配置环绕通知的组装。 注意:前置通知和后置通知和环绕通知可以同时使用,执行顺序和配置顺序相关。
SchemaBase方式的异常通知
问题:
在我们封装一个功能方法时,一般方法处理数据所造成的异常信息需要抛出,或者 代码编译没有问题,运行期间出现问题,该异常也应该有调用者来处理。那么在Spring AOP中,代理对象是动态生成的,在代理对象中会调用前置通知,后置通知,环绕通 知,切点方法,那么如果这些方法出现异常信息,理论上来说应该在扩展对象中的扩展 方法中完成异常的处理。但是尴尬的是,代理对象是动态生成的,不是由我们创建类然 后根据类文件创建出来的,那么我们就无法直接的声明异常处理代码了,怎么办呢?
解决:
在外部声明异常处理的功能方法,让SpringAOP动态生成的代理对象,在生成的catch中调用我们声明的异常处理方法即可。
使用:
①创建一个普通Java类,实现异常接口。
写一个类,类里面的方法必须是这样写,必须方法名字是afterThrowing,他是接口里面的方法,但是继承了这个接口是不会提示的。
代码语言:javascript复制public class MyThrow implements ThrowsAdvice {
public void afterThrowing(Exception e){
System.out.println("我是异常通知:" e.getMessage());
}
}
写完之后将这个类在xml里面配置bean对象,并且进行对象的组装就可以了。
②在applicationcontext.xml文件中配置异常通知bean对象
③在applicationcontext.xml文件中配置异常通知bean的组装
SpringAOP的SchemaBase方法的参数
前置通知
使用: ①声明一个普通Java类,实现BeforeAdvice接口。 ②在Spring配置文件中配置前置通知的bean对象 ③配置组装 方法: 方法名:before 调用者:代理对象中的扩展方法调用 方法体:声明切点之前执行的扩展代码 参数: Method method, Object[] objects, Object o 参数的作用:
[2]后置通知
使用: ①声明一个普通Java类,实现AfterReturningAdvice接口。 ②在Spring配置文件中配置后置通知的bean对象 ③配置组装 方法: 方法名:after 调用者:代理对象中的扩展方法调用 方法体:声明切点之后执行的扩展代码 参数: Object o, Method method, Object[] objects, Object o1 参数的作用:
[3]环绕通知
使用: ①声明一个普通Java类,实现MethodInterceptor接口。 ②在Spring配置文件中配置环绕通知的bean对象 ③配置组装 方法: 方法名:invoke 调用者:代理对象中的扩展方法调用 方法体:声明扩展代码同时根据需求是否放行。 参数: MethodInvocation methodInvocation 参数的作用:
[4]异常通知
使用: ①声明一个普通Java类,实现ThrowAdvice接口。 ②在Spring配置文件中配置异常通知的bean对象 ③配置组装 方法: 方法名:afterThrowing 调用者:代理对象中的扩展方法的catch中调用 方法体:根据异常信息处理异常。 参数: Exception ex 参数的作用: 获取异常信息