Spring6 AOP2 ADVICE

来源:互联网 发布:期货交易软件开发 编辑:程序博客网 时间:2024/06/10 04:23
1、 around advice:所有around advice必须实现MethodInterceptor接口,注意invoke方法的参数invocation是MethodInvocation接口,在此中包含了许多信息,包括其所封装的方法及其参数,AOP proxy、Jointcut等。
public interface MethodInterceptor extends Interceptor {
                  Object invoke(MethodInvocation invocation) throws Throwable;
}
    在实现around advice时,和before advice、after advice有着两个很大的区别:1、必须在invoke方法中调用MethodInvocation.proceed(),这样才能将所有调用延续下去,调用target对象的method2、必须自己返回一个object,该object甚至可以与target’s method的返回值不一样。
 
2、 before advice:在jointcut执行之前,运行advice。必须实现MethodBeforeAdvice接口。
public interface MethodBeforeAdvice extends BeforeAdvice {
    void before(Method m, Object[] args, Object target) throws Throwable;
}
3、 after advice:在jointcut执行之后,运行advice。必须实现AfterReturningAdvice接口。
public interface AfterReturningAdvice extends Advice {
    void afterReturning(Object returnValue, Method m, Object[] args, Object target)
            throws Throwable;
}
4、 throws advice:在jointcut执行出现异常的时候,运行此advice。必须实现ThrowsAdvice接口。但是此接口只是一个标识接口,必须实现此外实现下面的方法: 
afterThrowing([Method], [args], [target], subclassOfThrowable)

   此外,在jointcut出现异常时,具体调用哪个afterThrowing方法,这就涉及到类型判别,最符合类型判别的将会被调用Spring

Advice types in spring

AOP
通知类型
1、BeforeAdvice:前置通知需实现MethodBeforeAdvice,但是该接口的Parent是BeforeAdvice,致于什么用处我想可能是扩展性需求的设计吧。或者
Spring未来也并不局限于Method的JoinPoint(胡乱猜测)。BeforeAdvice可以修改目标的参数,也可以通过抛出异常来阻止目标运行。

2、AfterreturningAdvice:实现AfterreturningAdvice,我们无法修改方法的返回值,但是可以通过抛出异常阻止方法运行。

3、AroundAdvice:
Spring 通过实现MethodInterceptor(aopalliance)来实现包围通知,最大特点是可以修改返回值,当然它在方法前后都加入了自己的逻辑代码,因此功能异常强大。通过MethodInvocation.proceed()来调用目标方法(甚至可以不调用)。

4、ThrowsAdvice:通过实现若干afterThrowing()来实现。

5、IntroductionInterceptor:
Spring 的默认实现为DelegatingIntroductionInterceptor

Advice type Interface Descritpion Around org.aopalliance.intercept.MethodInterceptor Intercepts calls to the target
method
Before

org.springframework.aop.BeforeAdvice

org.springframework.aop.MethodBeforeAdvice

 

Called before the target
method is invoked
After org.springframework.aop.AfterReturningAdvice Called after the target
method returns
Throws org.springframework.aop.ThrowsAdvice Called when target
method throws an
exception
实现MethodBeforeAdvice接口。
java 代码

 //逻辑业务接口

package study.spring.lesson04.advice;

public interface ILogin {
 boolean login(String username,String password);

}

//目标类(被代理的类)包含核心逻辑业务 

package study.spring.lesson04.advice;

public class LoginAction implements ILogin{

 public boolean login(String username, String password) {

  if ("zhangsan".equals(username))
   throw new RuntimeException();
  else if ("lisi".equals(username) && "1234".equals(password))

   return true;
  else

   return false;

 }
}

//实现methodBeforAdvice

package study.spring.lesson04.advice;

import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.MethodBeforeAdvice;

public class LoginBeforAdvice implements MethodBeforeAdvice {//必须实现此方法

  private Log log = LogFactory.getLog(LoginBeforAdvice.class);
                                 
 public void before(Method method, Object[] args, Object target)//通知的具体实现
   throws Throwable {
  if(ILogin.class.isAssignableFrom(target.getClass())){
   String username = (String)args[0];
   log.info("User[" + username + "]is logining");
  }

 }

}

    代理类调用方法时,真正运行的是每个目标类的真正方法,会根据XML当中配置的接口查询相应的实现了methodBeforAdvice方法的类然后运行,再运行目标类的真正业务逻辑方法,args包含了该方法所有的参数。

xml 代码

 <?xml version="1.0"  encoding="GBK" ?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
  "
http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="loginTarget" class="study.spring.lesson04.advice.LoginAction"/>
<bean id="loginBeforeAdvice" class="study.spring.lesson04.advice.LoginBeforAdvice"/>
<bean id="login" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">   //目标类的指定
<ref local="loginTarget"/>
</property>
<property name="proxyInterfaces">   //应用通知的接口
<value>study.spring.lesson04.advice.ILogin</value>
</property>
<property name="interceptorNames"> //通知的指定
<list>
<value>loginBeforeAdvice</value>
</list>
</property>
</bean>

</beans>

测试类

 package test.study.spring.lesson04;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import study.spring.lesson04.advice.ILogin;

import junit.framework.TestCase;

public class TestAop extends TestCase {

 public void testAop(){
  Resource res = new ClassPathResource("beans.xml");
  BeanFactory bf = new XmlBeanFactory(res);
  ILogin login =(ILogin) bf.getBean("login");   //运用了FactoryBean当中的getObject方法
  login.login("lisi", "1234");                             //运用了Proxy.newProxyInstance方法
  
 }
}

    org.springframework.aop.framework.ProxyFactoryBean是spring框架中很重要的一个类,它可以在不改变被代理类的前提下对其增加一些行为。

 实现AfterReturningAdvice接口

java 代码

 //逻辑业务接口

package study.spring.lesson04.advice;

public interface ILogin {
 boolean login(String username,String password);

}

//目标类(被代理的类)包含核心逻辑业务 

package study.spring.lesson04.advice;

public class LoginAction implements ILogin{

 public boolean login(String username, String password) {

  if ("zhangsan".equals(username))
   throw new RuntimeException();
  else if ("lisi".equals(username) && "1234".equals(password))

   return true;
  else

   return false;

 }
}

//实现AfterReturningAdvice接口

package study.spring.lesson04.advice;

import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.AfterReturningAdvice;

public class LoginAfterAdvice implements AfterReturningAdvice {

 private Log log = LogFactory.getLog(LoginAfterAdvice.class);

 public void afterReturning(Object returnvalue, Method method,
   Object[] args, Object target) throws Throwable {

  if (ILogin.class.isAssignableFrom(target.getClass())) {
   boolean flag = (Boolean) returnvalue;
   String username = (String) args[0];
   if (flag)
    log.info("User[" + username + "] login success");
   else
    log.info("User[" + username + "] login failed");

  }
 }

}
xml 代码

<?xml version="1.0"  encoding="GBK" ?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
  "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="loginTarget" class="study.spring.lesson04.advice.LoginAction"/>
<bean id="loginBeforeAdvice" class="study.spring.lesson04.advice.LoginBeforAdvice"/>
<bean id="login" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="loginTarget"/>
</property>
<property name="proxyInterfaces">
<value>study.spring.lesson04.advice.ILogin</value>
</property>
<property name="interceptorNames">
<list>
<value>loginBeforeAdvice</value>
<value>LoginAfterAdvice</value>   //
</list>
</property>
</bean>
<bean id="LoginAfterAdvice" class="study.spring.lesson04.advice.LoginAfterAdvice"/>
</beans>

实现ArondAdvice接口

java 代码

 //逻辑业务接口

package study.spring.lesson04.advice;

public interface ILogin {
 boolean login(String username,String password);

}

//目标类(被代理的类)包含核心逻辑业务 

package study.spring.lesson04.advice;

public class LoginAction implements ILogin{

 public boolean login(String username, String password) {

  if ("zhangsan".equals(username))
   throw new RuntimeException();
  else if ("lisi".equals(username) && "1234".equals(password))

   return true;
  else

   return false;

 }
}

//实现ArondAdvice接口

package study.spring.lesson04.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LoginAroundAdvice implements MethodInterceptor {  //必须实现此接口

 private Log log = LogFactory.getLog(LoginAroundAdvice.class);

 public Object invoke(MethodInvocation invocation) throws Throwable {
  
  if (ILogin.class.isAssignableFrom(invocation.getMethod()
    .getDeclaringClass())) {
  
   String username = (String) invocation.getArguments()[0];
        
   log.info("User[" + username + "]is logining");
   
   if ((Boolean) invocation.proceed()) {      //此处可以控制目标对象的方法的调用
   
    log.info("User[" + username + "] login success");
    return true;
   } else {
    
    log.info("User[" + username + "] login failed");
    return false;
   }

  }
  return invocation.proceed();
 }

}
xml代码实现

<?xml version="1.0"  encoding="GBK" ?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
  "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="loginTarget" class="study.spring.lesson04.advice.LoginAction"/>
<bean id="loginBeforeAdvice" class="study.spring.lesson04.advice.LoginBeforAdvice"/>
<bean id="login" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="loginTarget"/>
</property>
<property name="proxyInterfaces">
<value>study.spring.lesson04.advice.ILogin</value>
</property>
<property name="interceptorNames">
<list>
<value>loginBeforeAdvice</value>
<value>LoginAfterAdvice</value>
 <value>LoginAroundAdvice</value>
</list>
</property>
</bean>
<bean id="LoginAfterAdvice" class="study.spring.lesson04.advice.LoginAfterAdvice"/>
 <bean id="LoginAroundAdvice" class="study.spring.lesson04.advice.LoginAroundAdvice"/>
</beans>

原创粉丝点击