学习Spring第五天

Author Avatar
人不如故 10月 24, 2017
  • 在其它设备中阅读本文章

BeanNameAutoProxyCreator

生产中会有会多bean需要代理,为了节约时间和减少工作量,我们可以使用自动代理来创建代理Bean

个人感觉十分简单

首先创建一个BeanNameAutoProxyCreator的Bean,然后把Advisor和需要代理的Bean丢进去(支持正则匹配)

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
        <list>
            <value>*Service</value>
        </list>
    </property>
    <property name="interceptorNames">
        <list>
            <value>customerPointCut</value>
            <value>customerAdvisor</value>
        </list>
    </property>
</bean>

然后测试类不需要在调用Proxy的名字,直接使用,Spring会自动创建代理

DefaultAdvisorAutoProxyCreator

听说十分强大,如果有Bean相关联,会自动创建相应的代理

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

一行代码即可,感觉是有点方便,运行结果不变

  • 拦截器的序列会影响结果,我们需要自己调整顺序如果是使用BeanNameAutoProxyCreator

AOP+AspectJ 面向切面编程

AspectJ常见的注解

@Before – 方法执行前运行
@After – 运行在方法返回结果后
@AfterReturning – 运行在方法返回一个结果后,在拦截器返回结果。
@AfterThrowing – 运行方法在抛出异常后,
@Around – 围绕方法执行运行,结合以上这三个通知。

创建一个Dao

package com.demo.Dao;

public interface CustomerBo {
    void addCustomer();

    String addCustomerReturnValue();

    void addCustomerThrowException() throws Exception;

    void addCustomerAround(String name);
}

实现类CustomerBoImpl

package com.demo.Dao.Impl;

import com.demo.Dao.CustomerBo;

public class CustomerBoImpl implements CustomerBo {
    @Override
    public void addCustomer() {
        System.out.println("addCustomer() is running");
    }

    @Override
    public String addCustomerReturnValue() {
        System.out.println("addCustomerReturnValue() is running");
        return "abc";
    }

    @Override
    public void addCustomerThrowException() throws Exception {
        System.out.println("addCustomerThrowException() is running");

        throw new Exception("Generic Error");
    }

    @Override
    public void addCustomerAround(String name) {
        System.out.println("addCustomerAround(String name) is running, args: " + name);
    }
}

然后定义一个AspectJ用来输出日志信息

package com.demo.AspectJ;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

    @Before("execution(* com.demo.Dao.CustomerBo.addCustomer(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("logBefore() is running");
        System.out.println("Method " + joinPoint.getSignature().getName());
        System.out.println("**********");
    }
}

在applicationContext.xml中声明Beans

<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-4.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd ">

    <aop:aspectj-autoproxy/>

    <bean id="customerBo" class="com.demo.Dao.Impl.CustomerBoImpl"/>

    <bean id="logAspect" class="com.demo.AspectJ.LoggingAspect"/>
</beans>

这里用到了<aop:aspectj-autoproxy/>开启切片自动拦截

然后在xml中注册了这个日志拦截切片

运行结果如下:

下面把其余的几个注解一起使用

package com.demo.AspectJ;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Arrays;

@Aspect
public class LoggingAspect {

    @Before("execution(* com.demo.Dao.CustomerBo.addCustomer(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("logBefore() is running");
        System.out.println("Method " + joinPoint.getSignature().getName());
        System.out.println("**********");
    }

    @After("execution(* com.demo.Dao.CustomerBo.addCustomer(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("logAfter() is running");
        System.out.println("Method " + joinPoint.getSignature().getName());
        System.out.println("**********");
    }

    @AfterReturning("execution(* com.demo.Dao.CustomerBo.addCustomerReturnValue(..))")
    public void logAfterReturn(JoinPoint joinPoint) {
        System.out.println("logAfterReturn() is running");
        System.out.println("Method " + joinPoint.getSignature().getName());
        System.out.println("**********");
    }

    @AfterThrowing(pointcut = "execution(* com.demo.Dao.CustomerBo.addCustomerThrowException(..))", throwing = "error")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
        System.out.println("logAfterThrowing() is running");
        System.out.println("Method : " + joinPoint.getSignature().getName());
        System.out.println("Error : " + error);
        System.out.println("**********");
    }

    @Around("execution(* com.demo.Dao.CustomerBo.addCustomerAround(..))")
    public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("logAround() is running");
        System.out.println("Method : " + joinPoint.getSignature().getName());
        System.out.println("Method Parameters : " + Arrays.toString(joinPoint.getArgs()));
        System.out.println("Around Before is running");
        joinPoint.proceed();
        System.out.println("Around After is running");
        System.out.println("**********");
    }

}

感觉跟写Advice差不多

流程就是这样: DaoImpl->AspectJ->xml开启aspect自动代理->xml注入->调用

  • 注解可以用xml代替
<aop:before> = @Before
<aop:after> = @After
<aop:after-returning> = @AfterReturning
<aop:after-throwing> = @AfterThrowing
<aop:after-around> = @Around
<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-4.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd ">

    <aop:aspectj-autoproxy/>

    <bean id="customerBo" class="com.demo.Dao.Impl.CustomerBoImpl"/>

    <bean id="logAspect" class="com.demo.AspectJ.LoggingAspect"/>
    <aop:config>
        <aop:aspect id="aspectLogging" ref="logAspect">
            <aop:pointcut id="pointCutBefore" expression="execution(* com.demo.Dao.CustomerBo.addCustomer(..))"/>
            <aop:before method="logBefore" pointcut-ref="pointCutBefore"/>

            <aop:pointcut id="pointCutAfter" expression="execution(* com.demo.Dao.CustomerBo.addCustomer(..))"/>
            <aop:after method="logAfter" pointcut-ref="pointCutAfter"/>
        </aop:aspect>
    </aop:config>
</beans>

在xml中注册<aop:config>在内层用<aop:aspect>包裹,内部每声明一个pointcut就有一个响应的<aop:xxx>与之对应,我理解为一个切片,一个执行

坚持原创技术分享,您的支持将鼓励我继续创作!