(spring)AOP

2019-08-15  本文已影响0人  鸡龙

AOP的作用

在前几天学习到的spring中的java基础(AOP)通过java程序例子已经讲述了什么是AOP。

AOP的好处就是解除非核心功能且又在核心代码类中与核心类强耦合和非核心功能的代码冗余。

AOP中的主要概念

AOP实现

基于代理的AOP

基于代理的AOP是实现了三个接口MethodBeforeAdviceAfterReturningAdviceThrowsAdvice

public void afterThrowing(Exception ex)
public void afterThrowing(RomoteException ex)
public void afterThrowing(Method method,Object[] args,Object targer,Exception ex)
public void afterThrowing(Method method,Object[] args,Object targer,ServletException ex)

拦截器示范

IAOPServices

创建一个接口类IAOPServices,其中拦截器作用到withAopMethod方法。

public interface IAOPServices {
    public String withAopMethod() throws Exception;
    public String withNoAopMethod() throws Exception;
}
AOPServicesImpl

创建一个实现接口类AOPServicesImpl

public class AOPServicesImpl implements IAOPServices {
    private String description;
    public String getDescription(){
        return description;
    }
    public void setDescription(String description){
        this.description = description;
    }
    @Override
    public String withAopMethod() throws Exception {
        System.out.println("AOP函数运行方法:withAopMethod");
        if(description.trim().length()==0){
            throw new Exception("description属性不能为空");
        }
        return description;
    }

    @Override
    public String withNoAopMethod() throws Exception {
        System.out.println("无AOP函数运行方法:withNoAopMethod");
        return description;
    }
}
AOPInterceptor

创建一个拦截器类AOPInterceptor实现了上述提到的三个接口。

public class AOPInterceptor implements AfterReturningAdvice, 
        MethodBeforeAdvice,ThrowsAdvice {
    @Override
    public void afterReturning(Object o, Method method, 
                               Object[] objects, Object o1) throws Throwable {
        System.out.println("方法" + method.getName()
                + "运行结束,返回值为:"+ o);
    }

    @Override
    public void before(Method method, Object[] objects,
                       Object o) throws Throwable {
        System.out.println("执行MethodBeforeAdvice,即将执行的方法" 
                + method.getName());
        
        if(o instanceof AOPServicesImpl){
            String description = ((AOPServicesImpl)o).getDescription();
            if(description==null){
                throw new NullPointerException("description属性不能为Null");
            }
        }
    }
    //通过反射进行方法匹配ThrowsAdvice中并无抽象方法
    public void afterThrowing(Exception ex){
        System.out.println("抛出了异常:" + ex.getMessage());
    }
    public void afterThrowing(Method method ,Object[] args,
                              Object target,Exception ex) {
        System.out.println("方法" + method.getName() 
                + "抛出了异常:" + ex.getMessage());
    }
}
pom.xml引入依赖

在pom中添加依赖spring-aop,pom.xml中增加以下代码。

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.2.6.RELEASE</version>
    </dependency>
xml注入配置

实际上无法直接完成实现类与拦截器的直接组装,因为在拦截器中并没有对应的setter、getter方法,只能先将自定义拦截器注入NmaeMatchMethodPointcutAdvisor类的advice属性中,再将NameMatchMethodPointcutAdvisor对象注入到ProxyFactoryBean中。
这里将AOPInterceptor拦截器注入到NameMathcMethodPointcutAdvisor中。再将NameMathcMethodPointcutAdvisor对象注入到ProxyFactoryBean中。最后使用ProxyFactoryBean

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd

        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--    将拦截器注入到NameMatchMethodPointcutAdvisor-->
    <bean id="aopInterceptor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="advice">
            <bean class="test.basicAOP.AOPInterceptor"/>
        </property>
        <property name="mappedName" value="withAopMethod"/>
    </bean>
<!--将NameMatchMethodPointcutAdvisor注入到ProxyFactoryBean-->
    <bean id="aopService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="interceptorNames">
            <list>
                <value>aopInterceptor</value>
            </list>
        </property>
        <property name="target">
            <bean class="test.basicAOP.AOPServicesImpl">
                <property name="description" value="basicAOP"/>
            </bean>
        </property>
    </bean>
</beans>
main
public class AopTest {
    public static void main(String args[]) throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("basicAOP/app.xml");
        IAOPServices services = (IAOPServices)context.getBean("aopService");
        services.withAopMethod();
        services.withNoAopMethod();
    }
}
执行结果
执行MethodBeforeAdvice,即将执行的方法withAopMethod
AOP函数运行方法:withAopMethod
方法withAopMethod运行结束,返回值为:basicAOP
无AOP函数运行方法:withNoAopMethod

AspectJ基于XML

AspectJ是一个面向切面的框架,下表给出AspectJ主要的配置元素。

AOP配置元素 描述
<aop:config> 顶层的AOP配置元素,大多数的<aop:*>元素必须包含在<aop:config>元素内
<aop:aspect> 定义切面
<aop:aspect-autoproxy> 启动@AspectJ注解驱动的切面
<aop:pointcut> 定义切点
<aop:advisor> 定义AOP通知器
<aop:before> 定义AOP前置通知
<aop:after> 定义AOP后置通知
<aop:after-returning> 定义成功返回后的通知
<aop:after-throwing> 定义抛出异常后的通知
<aop:around> 定义AOP环绕通知
<aop:declare-parents 为被通知的对象引入额外的接口,并透明地实现

这里定义了XMLAdvice拦截器方法。用于演示前置、后置、成功返回、异常返回,环绕通知。

package test.Services;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class XMLAdvice {
    public void beforeAdvice(){
        System.out.println("前置通知执行了");
    }
    public void afterAdvice(){
        System.out.println("后置通知执行了");
    }
    public void afterReturnAdvice(String result){
        System.out.println("返回通知执行了" + "运行业务方法返回的结果为" + result);
    }
    public String aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        String result = "";
        try{
            System.out.println("环绕通知开始执行了");
            long start = System.currentTimeMillis();
            result = (String)proceedingJoinPoint.proceed();
            long end  = System.currentTimeMillis();
            System.out.println("环绕执行结束了");
            System.out.println("执行业务方法共计:" + (end - start) + "毫秒");
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
    public void throwingAdvice(JoinPoint joinPoint,Exception e){
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("异常通知执行了");
        stringBuffer.append("方法").append(joinPoint.getSignature().getName()).append("出现了异常");
        stringBuffer.append("异常信息为:").append(e.getMessage());
        System.out.println(stringBuffer.toString());
    }
}

AspectJ的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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="serviceImplA" class="test.basicAOP.AOPServicesImpl">
        <property name="description" value="basicAop"/>
    </bean>
    <bean id="serviceAspectBean" class="test.Services.XMLAdvice"/>
    <aop:config>
        <aop:aspect id="serviceAspect" ref="serviceAspectBean">
            <aop:pointcut id="servicePointcut" expression="execution(* test.basicAOP.*.withAop*(..))"/>
            <aop:before method="beforeAdvice" pointcut-ref="servicePointcut"/>
            <aop:after method="afterAdvice" pointcut-ref="servicePointcut"/>
            <aop:after-returning method="afterReturnAdvice" pointcut-ref="servicePointcut" returning="result"/>
            <aop:around method="aroundAdvice" pointcut-ref="servicePointcut" />
            <aop:after-throwing method="throwingAdvice" pointcut-ref="servicePointcut" throwing="e"/>
        </aop:aspect>
    </aop:config>
</beans>

注意这里的Aspectj切入点语法定义

execution(* test.basicAOP.*.withAop*(..))

分五个部分。

运行结果

前置通知执行了
环绕通知开始执行了
AOP函数运行方法:withAopMethod
环绕执行结束了
执行业务方法共计:0毫秒
返回通知执行了运行业务方法返回的结果为basicAop
后置通知执行了
无AOP函数运行方法:withNoAopMethod

AspectJ基于注解

@Component
@Aspect
public class AnnontationAdvice {
    @Before("execution(* test.basicAOP.*.withAop*(..))")
    public void beforeAdvice(){
        System.out.println("前置通知执行了");
    }
    @After("execution(* test.basicAOP.*.withAop*(..))")
    public void afterAdvice(){
        System.out.println("后置通知执行了");
    }
    @AfterReturning(value = "execution(* test.basicAOP.*.withAop*(..))",returning = "result")
    public void afterReturnAdvice(String result){
        System.out.println("返回通知执行了" + "运行业务方法返回的结果为" + result);
    }
    @Around("execution(* test.basicAOP.*.withAop*(..))")
    public String aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        String result = "";
        try{
            System.out.println("环绕通知开始执行了");
            long start = System.currentTimeMillis();
            result = (String)proceedingJoinPoint.proceed();
            long end  = System.currentTimeMillis();
            System.out.println("环绕执行结束了");
            System.out.println("执行业务方法共计:" + (end - start) + "毫秒");
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
    @AfterThrowing(value = "execution(* test.basicAOP.*.withAop*(..))",throwing = "e")
    public void throwingAdvice(JoinPoint joinPoint, Exception e){
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("异常通知执行了");
        stringBuffer.append("方法").append(joinPoint.getSignature().getName()).append("出现了异常");
        stringBuffer.append("异常信息为:").append(e.getMessage());
        System.out.println(stringBuffer.toString());
    }
}
<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="test.Services"/>
    <aop:aspectj-autoproxy/>
    <bean id="serviceImplA" class="test.basicAOP.AOPServicesImpl">
        <property name="description" value="basicAop"/>
    </bean>
    <bean id="serviceAspectBean" class="test.Services.XMLAdvice"/>
</beans>
环绕通知开始执行了
前置通知执行了
AOP函数运行方法:withAopMethod
环绕执行结束了
执行业务方法共计:0毫秒
后置通知执行了
返回通知执行了运行业务方法返回的结果为basicAop
无AOP函数运行方法:withNoAopMethod
上一篇 下一篇

猜你喜欢

热点阅读