前置增强:
使用一个程序来说明
1.定义一个服务生接口,服务生只做两件事:欢迎顾客和为顾客提供服务
public interface Waiter {
void greetTo(String name);//提供服务
void serveTo(String name);//为顾客服务
}
2.定义一个训练不足的服务生类,只是会简单向顾客打招呼,并直接提供服务,很羞涩啊
public class NaiveWaiter implements Waiter {
public void greetTo(String name) {
System.out.println("greet to " + name + "...");
}
public void serveTo(String name) {
System.out.println("serving " + name + "...");
}
}3.酒店经理对此服务生不满意,对其行为进行了规范,要求在打招呼和服务之前,要对顾客使用礼貌用语:
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object object) throws Throwable {
String clientName = (String) args[0];//顾客姓名
System.out.println("How are you ! Mr." + clientName);//对顾客进行礼貌问候
}
}
BeforeAdvice时前置增强的接口,MethodBeforeAdvice时方法前置增强的接口,是BeforeAdvice的子类 Spring目前只提供方法调用的前置增强MethodBeforeAdvice接口只定义了唯一的方法:public void before(Method method,Object[] args,Object object) throws Throwable; method 为目标类的方法;args为目标类方法的入参;object为目标类实例。该方法发生异常时会抛出异常并阻止后面目标类方法的执行。
4.对该Naive服务生进行测试:
public class BeforeAdviceTest {
private Waiter target;//要代理的目标
private BeforeAdvice beforeAdvice;//前置增强
private ProxyFactory proxyFactory;//代理工厂
public void init(){
target = new NaiveWaiter();//代理目标为菜鸡服务生
beforeAdvice = new GreetingBeforeAdvice();
proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);//设置要代理的目标
proxyFactory.addAdvice(beforeAdvice);//为代理目标添加增强
}
public void test(){
init();
Waiter waiterProxy = (Waiter) proxyFactory.getProxy();
waiterProxy.greetTo("Messi");
waiterProxy.serveTo("Ronaldo");
}
public static void main(String[] args) {
new BeforeAdviceTest().test();
}
}运行结果为:
How are you ! Mr.Messi -------------通过前置增强引入的礼貌用语
greet to Messi...
How are you ! Mr.Ronaldo --------------通过前置增强引入的礼貌用语
serving Ronaldo...
该服务生的服务水平得到显著提高。
通过在Spring配置文件中配置
beans.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" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 代理的目标对象 -->
<bean id="target" class="com.newsmart.advice.NaiveWaiter"/>
<!-- 前置增强 -->
<bean id="greetingBeforeAdvice" class="com.newsmart.advice.GreetingBeforeAdvice"/>
<!-- 代理 -->
<bean id="waiterProxy" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.newsmart.advice.Waiter"
p:interceptorNames="greetingBeforeAdvice"
p:target-ref="target"
/>
</beans>
beans.xml配置文件说明
1.配置代理目标类
2.配置前置增强
3.配置代理:
proxyInterfaces:配置代理目标实现的接口,多个接口使用<list>元素
interceptorNames: 需要植入目标对象的bean列表,即前置增强
target-ref:指定对哪个Bean进行代理,即步骤1配置的代理目标类
public class BeforeAdviceTest {
public void test() {
String configPath = "beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configPath);
Waiter waiterProxy = (Waiter) applicationContext.getBean("waiterProxy");
waiterProxy.greetTo("Messi");
waiterProxy.serveTo("Ronaldo");
}
public static void main(String[] args) {
new BeforeAdviceTest().test();
}
}后置增强:
经理又要求该服务生在服务完后对顾客进行礼貌问候
public class GreetingAfterAdvice implements AfterReturningAdvice {
//在目标类方法调用后执行
public void afterReturning(Object returnObject, Method method, Object[] args, Object object) throws Throwable {
System.out.println("Please enjoy yourself!");
}
}后置增强在目标类方法调用后执行
AfterAdvice是后置增强的接口,AfterReturningAdvice接口是其子类
AfterReturningAdvice接口也只定义了唯一的方法: public void afterReturning(Object returnObject, Method method, Object[] args, Object object) throws Throwable;returnObject为目标方法返回的结果;
method为目标累的方法;args为目标类的方法的入参;object为目标类的实例。
将该后置增强添加到配置文件中:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 代理的目标对象 -->
<bean id="target" class="com.newsmart.advice.NaiveWaiter"/>
<!-- 前置增强 -->
<bean id="greetingBeforeAdvice" class="com.newsmart.advice.GreetingBeforeAdvice"/>
<!-- 后置增强 -->
<bean id="greetingAfterAdvice" class="com.newsmart.advice.GreetingAfterAdvice"/>
<!-- 代理 -->
<bean id="waiterProxy" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.newsmart.advice.Waiter"
p:interceptorNames="greetingBeforeAdvice,greetingAfterAdvice"
p:target-ref="target"
/>
</beans>测试结果:
How are you ! Mr.Messi
greet to Messi...
Please enjoy yourself!
How are you ! Mr.Ronaldo
serving Ronaldo...
Please enjoy yourself!
环绕增强:
环绕增强允许在目标类方法调用前后织入横切逻辑,综合实现了前置,后置的功能
//环绕增强public class GreetingInterceptor implements MethodInterceptor {
//截取目标类方法的执行 并在调用前后添加横切逻辑
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object[] args = methodInvocation.getArguments(); //获取目标方法的入参
String clientName = (String) args[0];
System.out.println("How are you ! Mr." + clientName);//对顾客进行礼貌问候 目标方法调用前执行
Object returnObject = methodInvocation.proceed(); //通过反射机制调用目标方法
System.out.println("Please enjoy yourself!"); //目标方法调用后执行
return returnObject;
}
}
public Object invoke(MethodInvocation methodInvocation) throws Throwable;通过methodInvocation封装目标方法,入参数组和目标实例对象。
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 代理的目标对象 -->
<bean id="target" class="com.newsmart.advice.NaiveWaiter"/>
<!-- 环绕增强 -->
<bean id="greetingAround" class="com.newsmart.advice.GreetingInterceptor"/>
<!-- 代理 -->
<bean id="waiterProxy" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.newsmart.advice.Waiter"
p:interceptorNames="greetingAround"
p:target-ref="target"
/>
</beans>测试结果:
How are you ! Mr.Messi
greet to Messi...
Please enjoy yourself!
How are you ! Mr.Ronaldo
serving Ronaldo...
Please enjoy yourself!
异常抛出增强:
异常抛出增强最适合的应用场景是事务管理。但某个事务异常时,事务管理器就必须回滚事务。
public class Service {
public void delete(int id) {
throw new RuntimeException("运行时异常");
}
public void update() throws Exception {
// do sth
throw new SQLException("数据更新操作异常");
}
}异常抛出增强:
异常抛出增强最适合的应用场景是事务管理。在某个事务异常时,事务管理器就必须回滚事务。
ThrowAdvice异常抛出增强接口没有定义任何方法,需要自行定义方法:
public void afterThrowing(Method method, Object[] args,Object target,Throwable e);
前三个入参可选,要么都有,要么都没有;最后一个必须为Throwable或其子类。
public class TransactionManager implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args,Object target,Exception e){
System.out.println("-----------------------");
System.out.println("method:" + method.getName());
System.out.println("抛出异常:" + e.getMessage());
System.out.println("成功回滚事务");
System.out.println("------------------------");
}
}配置文件:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 异常抛出增强 -->
<bean id="transactionManager" class="com.newsmart.advice.TransactionManager"/>
<!---->
<bean id="serviceTarget" class="com.newsmart.advice.Service"/>
<!---->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="transactionManager"
p:target-ref="serviceTarget"
p:proxyTargetClass="true"/>
</beans>编写测试方法:
public class ThrowAdviceTest {
public void test() throws Exception {
String configPath = "beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configPath);
Service serviceProxy = (Service) applicationContext.getBean("serviceProxy");
serviceProxy.delete(1);
}
public static void main(String[] args) {
try {
new ThrowAdviceTest().test();
} catch (Exception e) {
e.printStackTrace();
}
}
}
-----------------------
method:delete
抛出异常:运行时异常
成功回滚事务
------------------------
2万+

被折叠的 条评论
为什么被折叠?



