Spring AOP之ProxyFactoryBean与BeanNameAutoProxyCreator

本文介绍了Spring AOP中如何使用ProxyFactoryBean和BeanNameAutoProxyCreator创建代理对象。首先,讲解了业务接口和实现类的准备,接着详细阐述了方法拦截器(通知)的编写。然后,通过ProxyFactoryBean的配置和测试展示了基本的AOP应用。进一步,文章提到了更灵活的正则切入点,并用BeanNameAutoProxyCreator自动为满足条件的bean创建代理,避免了对每个业务类单独配置。最后,介绍了AspectJExpressionPointcutAdvisor,它允许更精确的切点表达式,包括包名、类名、方法名等,从而减少了配置的复杂性。

准备业务接口和实现类

package org.lanqiao.springDemo.aop;

public interface SomeBiz {
  public void addBiz();
  public void other();
}
package org.lanqiao.springDemo.aop;

public class SomeBizImpl implements SomeBiz{
  public void addBiz(){
    System.out.println("新增数据的业务逻辑");
  }
  public void other(){
    System.out.println("其他方法");
  }
}

编写方法拦截器(通知)

package org.lanqiao.springDemo.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class Advice1 implements MethodInterceptor {
  public Object invoke(MethodInvocation methodInvocation) throws Throwable {
    System.out.printf("代理逻辑发生在调用方法%s之前\n", methodInvocation.getMethod().toGenericString());
    return methodInvocation.proceed();
  }
}

ProxyFactoryBean基本配置

<!--通知-->
  <bean id="advice1" class="org.lanqiao.springDemo.aop.Advice1" />

  <!--切面组合-->
  <bean class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor" id="advisor1">
    <property name="advice" ref="advice1"/>
  <!--这里不是正则表达式而是简单的通配-->
    <property name="mappedName" value="*Biz"/>
  </bean>

  <bean id="someBiz" class="org.lanqiao.springDemo.aop.SomeBizImpl"/>

  <!--声明代理-->
  <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="someBizProxy">
    <!--指定接口-->
    <property name="proxyInterfaces" value="org.lanqiao.springDemo.aop.SomeBiz"/>
    <!--指定实现类-->
    <property name="target" ref="someBiz"/>
    <!--拦截器名字-->
    <property name="interceptorNames">
      <list>
        <value>advisor1</value>
      </list>
    </property>
  </bean>

测试

package org.lanqiao.springDemo.aop;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;

@ContextConfiguration("classpath:aop.xml")
public class SomeBizImplTest extends AbstractJUnit4SpringContextTests {
  @Autowired
  private SomeBiz someBizProxy;

  @org.junit.Test
  public void addBizUsingInterfaceProxy() throws Exception {
    someBizProxy.addBiz();
  }
}

结果:

代理逻辑发生在调用方法public abstract void org.lanqiao.springDemo.aop.SomeBiz.addBiz()之前
新增数据的业务逻辑

使用更强大的正则切入点

使用JdkRegexpMethodPointcut

<!--通知-->
  <bean id="advice1" class="org.lanqiao.springDemo.aop.Advice1" />


<bean id="regexpAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
  <property name="advice" ref="advice1"/>
  <property name="pointcut">
    <bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
      <!--这里可以使用正则表达式-->
      <property name="pattern" value=".*Biz.*" />
    </bean>
  </property>
</bean>

  <bean id="someBiz" class="org.lanqiao.springDemo.aop.SomeBizImpl"/>

  <!--声明代理-->
  <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="someBizProxy">
    <!--指定接口-->
    <property name="proxyInterfaces" value="org.lanqiao.springDemo.aop.SomeBiz"/>
    <!--指定实现类-->
    <property name="target" ref="someBiz"/>
    <!--拦截器名字-->
    <property name="interceptorNames">
      <list>
        <value>regexpAdvisor</value>
      </list>
    </property>
  </bean>

测试效果同上

使用更强大的可以通配beanName的BeanNameAutoProxyCreator

上例的缺点在于,对于每个业务类我们都要配一个ProxyFactoryBean,接下来我们使用更为强大的BeanNameAutoProxyCreator来自动为满足通配条件的bean生产代理,而且在依赖业务类的地方直接使用原始beanName即可:

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <!--拦截器名字-->
    <property name="interceptorNames">
      <list>
        <value>regexpAdvisor</value>
      </list>
    </property>
    <!--bean的名字可以用通配符-->
    <property name="beanNames" value="*Biz"/>
  </bean>

这样配置后,我们不需要ProxyFactoryBean,依赖业务bean时,也直接依赖原始bean的名字:

@Autowired
  private SomeBiz someBiz;

  @org.junit.Test
  public void addBizUsingBean() throws Exception {
    someBiz.addBiz();
  }

还有更强大的AspectJExpressionPointcutAdvisor

其他配置都不要,配置如下

<!--通知-->
  <bean id="advice1" class="org.lanqiao.springDemo.aop.Advice1" />
  <!--业务bean-->
  <bean id="someBiz" class="org.lanqiao.springDemo.aop.SomeBizImpl"/>

  <bean id="aspectAdvisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
    <property name="advice" ref="advice1"/>
    <!--切入点表达式-->
    <property name="expression" value="execution( * org.lanqiao.springDemo..*Biz*.*Biz(..))" />
  </bean>
  <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

因为我们的表达式可以直接指定包名、类名、方法名甚至参数类型、返回值类型等,所以不再需要基于bean名称的代理,必须开启自动代理:DefaultAdvisorAutoProxyCreator

希望有帮助,转载无需授权!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值