Spring笔记07(Spring AOP的通知advice和顾问advisor)
1.Spring AOP的通知advice
01.接口代码:
package cn.pb.dao; public interface UserDao {
//主业务
String add();
//主业务
void del();
}
02.实现类代码:
package cn.pb.dao; public class UserDaoImpl implements UserDao{
//主业务
public String add() {
//模拟异常
//int a=8/0;
System.out.println("add ok!");
return "新增成功!";
}
//主业务
public void del() {
System.out.println("del ok!");
}
03.增强通知类:
001.前置增强类:
package cn.pb.advices;
/**
* 前置增强类 实现MethodBeforeAdvice接口
* 在目标对象方法执行之前执行
*/ import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class BeforeAdvice implements MethodBeforeAdvice {
/**
*
* @param method :目标方法
* @param args :目标方法参数
* @param target :目标对象
* @throws Throwable
*/
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("前置增强====================》");
}
}
002.后置增强类:
package cn.pb.advices;
/**
* 后置增强类 实现AfterReturningAdvice接口
* 在目标对象方法执行之后执行
*/
import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class AfterAdvice implements AfterReturningAdvice {
/**
*
* @param target:目标对象
* @param method :目标方法
* @param args :目标方法参数
* @param returnValue :目标方法返回值
* @throws Throwable
*/
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("后置增强==================》");
}
}
003.环绕增强类:
package cn.pb.advices;
/**
* 环绕增强 :
* 在前置通知 之后,
* 后置通知之前执行环绕通知!
*/ import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; public class AroundAdvice implements MethodInterceptor {
/**
* 在前置通知 之后,后置通知之前执行环绕通知!
* 可以获取方法的返回值,并且改变!
* @param methodInvocation 方法的执行器, getMethod 包含了方法中的所有方法
* @return
*/
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("执行方法之前的 环绕通知");
//执行目标方法
Object result= methodInvocation.proceed();
if (result!=null){
//对方法的返回值进行修改
result="xiaoheihei";
}
System.out.println("执行方法之后的 环绕通知");
return result;
}
}
004.异常增强类:
package cn.pb.advices; /**
* 异常增强类:在目标方法出现异常的时候执行
* 实现ThrowsAdvice接口
*/ import org.springframework.aop.ThrowsAdvice; public class ExceptionAdvice implements ThrowsAdvice{
public void throwsAdvice(){
System.out.println("方法在执行过程中出现了异常!");
}
}
04.applicationContext.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--01.配置目标对象-->
<bean id="userDao" class="cn.pb.dao.UserDaoImpl"/>
<!--02.配置通知-->
<bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/>
<bean id="afterAdvice" class="cn.pb.advices.AfterAdvice"/>
<bean id="aroundAdvice" class="cn.pb.advices.AroundAdvice"/> <!--03.通过配置代理工厂bean,生成代理类,来把通知织入到目标对象
问题:只能管理 通知!
01.只能将切面织入到目标类的所有方法中!
02.只能配置一个 目标对象
-->
<bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--注册目标对象 如果nam为target 那么ref="userDao" -->
<property name="targetName" value="userDao"/>
<!--注册通知-->
<property name="interceptorNames" value="beforeAdvice,afterAdvice,aroundAdvice"/> </bean> <!--配置异常目标对象-->
<bean id="userException" class="cn.pb.exceptionPackage.UserServiceImpl"/>
<!--配置异常通知-->
<bean id="myException" class="cn.pb.advices.ExceptionAdvice"/> <!--现在是一个service对应一个ProxyFactoryBean 这样不可以!-->
<bean id="exceptionProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--注册目标对象 -->
<property name="targetName" value="userException"/>
<!--注册通知-->
<property name="interceptorNames">
<array>
<value>myException</value> <!--异常通知-->
</array>
</property>
<!--代理类的优化 设置之后程序就会自动选择是使用JDK动态代理还是使用cglib动态代理-->
<property name="optimize" value="true"/>
<!-- <property name="proxyTargetClass" value="true"/>
proxyTargetClass:默认是false ,默认执行jdk动态代理!
设置成true,强制执行cglib!
optimize : 代理类的优化
有接口就是用jdk,没有接口使用cglib动态代理-->
</bean>
<!--
我们的动态代理 (在程序运行期间,动态生成的代理类) 分为两种方式:
01.jdk 只能应用于实现接口的情况
02.cglib 应用于实现接口和类的情况
如果我们是接口的情况,使用jdk效率高!
如果我们是类的情况,必须使用cglib!
问题?
程序 spring容器怎么知道我们是用的类还是接口??
public class ProxyConfig implements Serializable
private boolean proxyTargetClass = false;
private boolean optimize = false;
spring底层默认使用cglib! 现在我们的项目中使用的是接口!
用spring默认的性能不高!
proxyTargetClass 和optimize都是用来设置 我们使用的代理模式是jdk还是cglib!
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
根据我们配置文件中 proxyTargetClass 和 optimize的配置
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
根据目标对象返回对应的动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
--> </beans>
05.测试代码:
package cn.pb; import cn.pb.dao.UserDao;
import cn.pb.exceptionPackage.ServiceException;
import cn.pb.exceptionPackage.UserException;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestAdvice { /**
* 前置 后置 通知测试
*/ @Test
public void testBefore(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao service= (UserDao) context.getBean("userProxy");
service.add();
System.out.println("*************");
service.del();
} /**
* 环绕 通知测试
*/ @Test
public void testAround(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao service= (UserDao) context.getBean("userProxy");
String result= service.add();
System.out.println(result);
System.out.println("*************");
service.del();
} /**
* 异常通知测试
*/ @Test
public void testException(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
ServiceException service= (ServiceException) context.getBean("exceptionProxy");
try {
service.chechUser("admins",25);
} catch (UserException e) {
e.printStackTrace();
} } }
2.Spring AOP的顾问advisor
01.readMe
顾问:在通知的基础之上,在细化我们的aop切面! 通知和顾问都是切面的实现方式!
通知是顾问的一个属性! 顾问会通过我们的设置,将不同的通知,在不通过的时间点,把切面
织入到不同的切入点! PointCutAdvisor接口!
比较常用的两个实现类:
NameMatchMethodPointcutAdvisor :根据切入点(主业务方法)名称织入切面!
RegexpMethodPointcutAdvisor :根据自定义的正则表达式织入切面! 正则表达式中常用的三个运算符
. 任意单个字符
+ 表示字符出现一次或者多次
* 表示字符出现0次或者多次
02.接口代码:
package cn.pb.dao; public interface UserDao {
//主业务
void add();
//主业务
void del();
}
03.实现类代码:
package cn.pb.dao.impl; import cn.pb.dao.UserDao; public class UserDaoImpl implements UserDao{ //主业务
public void add() {
System.out.println("add ok!");
}
//主业务
public void del() {
System.out.println("del ok!");
}
}
04.增强类代码:
package cn.pb.advices;
/**
* 前置增强类 在目标方法执行之前 执行
* 要实现MethodBeforeAdvice接口
*/ import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class BeforeAdvice implements MethodBeforeAdvice {
/**
* 在目标方法执行之前
* @param method 目标方法
* @param args 目标方法的参数列表
* @param target 目标对象
* @throws Throwable
*/
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("前置增强==============》");
}
}
05.applicationContext.xml文件:
001.NameMatchMethodPointcutAdvisor :根据切入点(主业务方法)名称织入切面!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--01.配置目标对象-->
<bean id="userDao" class="cn.pb.dao.impl.UserDaoImpl"/>
<!--02.配置增强 通知-->
<bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/> <!---配置顾问 实现了 在指定的主业务方法中 增强-->
<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!--通知就是顾问中的一个属性-->
<property name="advice" ref="beforeAdvice"/>
<!--配置切入点 这里的切入点指的是 方法的简写!-->
<property name="mappedNames" value="add,del"/>
</bean> <!--03.配置代理对象-->
<bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--注册目标对象-->
<property name="target" ref="userDao"/>
<!--注册顾问-->
<property name="interceptorNames" value="myAdvisor"/>
</bean> </beans>
002.RegexpMethodPointcutAdvisor :根据自定义的正则表达式织入切面!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--01.配置目标对象-->
<bean id="userDao" class="cn.pb.dao.impl.UserDaoImpl"/>
<!--02.配置增强 通知-->
<bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/> <!---配置顾问 实现了 在指定的主业务方法中 增强-->
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--通知就是顾问中的一个属性-->
<property name="advice" ref="beforeAdvice"/>
<!--配置切入点 这里的切入点指的是 方法的全限定方法名
cn.pb.dao.impl.UserServiceImpl.add
cn.pb.dao.impl.UserServiceImpl.del-->
<!-- <property name="pattern" value=".*add.*"/> 匹配单个方法-->
<!-- <property name="pattern" value=".*mpl.*"/>匹配多个方法-->
<!--<property name="patterns" value=".*add.*,.*del.*"/> 匹配多个方法-->
<property name="pattern" value=".*add.*|.*del.*"/> </bean> <!--03.配置代理对象-->
<bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--注册目标对象-->
<property name="target" ref="userDao"/>
<!--注册顾问-->
<property name="interceptorNames" value="myAdvisor"/>
</bean> </beans>
06.测试代码:
package cn.pb; import cn.pb.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestUser {
/**
* 测试NameMatchMethodPointcutAdvisor
*/
@Test
public void testNameMethod(){
ApplicationContext context=new
ClassPathXmlApplicationContext("applicationContext.xml");
UserDao proxy= (UserDao) context.getBean("userProxy");
proxy.add();
System.out.println("***************");
proxy.del();
} /**
* 测试RegexpMethodPointcutAdvisor
*/
@Test
public void testRegexpMethod(){
ApplicationContext context=new
ClassPathXmlApplicationContext("regexp.xml");
UserDao proxy= (UserDao) context.getBean("userProxy");
proxy.add();
System.out.println("***************");
proxy.del();
}
}
Spring笔记07(Spring AOP的通知advice和顾问advisor)的更多相关文章
- Spring笔记(4) - Spring的编程式事务和声明式事务详解
一.背景 事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作 ...
- Spring笔记1——Spring起源及其核心技术
Spring的作用 当我们使用一种技术时,需要思考为什么要使用这门技术.而我们为什么要使用Spring呢?从表面上面SSH这三大框架中,Struts是负责MVC责任的分离,并且提供为Web层提供诸如控 ...
- Spring笔记(7) - Spring的事件和监听机制
一.背景 事件机制作为一种编程机制,在很多开发语言中都提供了支持,同时许多开源框架的设计中都使用了事件机制,比如SpringFramework. 在 Java 语言中,Java 的事件机制参与者有3种 ...
- Spring笔记(6) - Spring的BeanFactoryPostProcessor探究
一.背景 在说BeanFactoryPostProcessor之前,先来说下BeanPostProcessor,在前文Spring笔记(2) - 生命周期/属性赋值/自动装配及部分源码解析中讲解了Be ...
- spring笔记3 spring MVC的基础知识3
4,spring MVC的视图 Controller得到模型数据之后,通过视图解析器生成视图,渲染发送给用户,用户就看到了结果. 视图:view接口,来个源码查看:它由视图解析器实例化,是无状态的,所 ...
- 011-Spring aop 002-核心说明-切点PointCut、通知Advice、切面Advisor
一.概述 切点Pointcut,切点代表了一个关于目标函数的过滤规则,后续的通知是基于切点来跟目标函数关联起来的. 然后要围绕该切点定义一系列的通知Advice,如@Before.@After.@Af ...
- Spring笔记——使用Spring进行面向切面(AOP)编程
要进行AOP编程,首先我们要在spring的配置文件中引入aop命名空间: =================== Spring提供了两种切面声明方式,实际工作中我们可以选用其中一种: 1. 基于XM ...
- 【Spring实战】—— 9 AOP环绕通知
假如有这么一个场景,需要统计某个方法执行的时间,如何做呢? 典型的会想到在方法执行前记录时间,方法执行后再次记录,得出运行的时间. 如果采用Spring的AOP,仅仅使用前置和后置方法是无法做到的,因 ...
- Spring笔记06(Spring AOP的底层实现动态代理)
1.代理模式readMe: 代理设计模式: 是java中常用的设计模式! 特点: .委托类和代理类有相同的接口或者共同的父类! .代理类为委托类负责处理消息,并将消息转发给委托类! .委托类和代理类对 ...
随机推荐
- wcf上传字节数组报错问题
为了实现上传大文件所以我们要如下设置最大值,其中security是设置访问服务的认证,此处是把它设置成为不认证,transferMode就是设置运用流的模式 <webHttpBinding> ...
- Codeforces Hello2015第一题Cursed Query
英文题面: De Prezer loves movies and series. He has watched the Troy for like 100 times and also he is a ...
- nodejs初学-----helloworld
近期紧锣密鼓的学习了下nodejs(之前在学php.算入门了吧,可是时间关系,还没写文章,兴许要搞安卓和大数据,总之比較忙哈,计划上php要排到后面了,还请广大小伙伴不要着急) 先抄一句:Node.j ...
- jquery 获取 outerHtml
在开发过程中,jQuery.html() 是获取当前节点下的html代码,并不包括当前节点本身的代码,然后我们有时候确须要.找遍jQuery api文档也没有不论什么方法能够拿到. 看到有的人通过pa ...
- Linux下实现RAID
一.实验目的 1.掌握Linux系统下软RAID的实现方法: 2.掌握RAID5的配置过程: 3. 通过实验熟悉RAID.5的特点. 二.实验内容及步骤 1.在VMware中创建一台Linux. 2. ...
- linux history 命令 禁用history
保存在.bash_history文件中,默认1000条,你也可以更改这个 值 !!:上一个指令 !number 运行第几个指令 查看命令历史的时间戳,那么可以执行: # export HISTTIME ...
- yii2学习笔记
之前看过Yii2框架,也在其他框架实现其Gii手脚架功能,现在开始使用Yii做项目,顺便记录一下学习笔记 先推荐一个网址 Yii2速查表(中文版)http://nai8.me/tool-sc.html ...
- LoadRunner性能测试过程/流程
用LoadRunner进行负载测试的流程通常由五个阶段组成:计划.脚本创建.场景定义.场景执行和结果分析.(1)计划负载测试:定义性能测试要求,例如并发用户的数量.典型业务流程和所需响应时间.(2)创 ...
- c++动态绑定的技术实现
1 什么是动态绑定 有一个基类,两个派生类,基类有一个virtual函数,两个派生类都覆盖了这个虚函数.现在有一个基类的指针或者引用,当该基类指针或者引用指向不同的派生类对象时,调用该虚函数,那么最终 ...
- 我的Java开发学习之旅------>Java经典排序算法之二分插入排序
一.折半插入排序(二分插入排序) 将直接插入排序中寻找A[i]的插入位置的方法改为采用折半比较,即可得到折半插入排序算法.在处理A[i]时,A[0]--A[i-1]已经按关键码值排好序.所谓折半比较, ...