浅析Spring AOP(面向方面编程)

SpringAOP提供的优势
1、允许开发者声明企业级服务,比如:事务服务、安全性服务。EJB组件能够使用J2EE容器提供声明式服务。但是需要借助于EJB组件,而SpringAOP却不需要EJB容器,即借助于Spring的事务抽象框架能够在EJB容器外部使用企业级、声明式服务。
2、开发者可以开发满足业务需求的自定义方面。类似于JBOSS服务器中拦截器开发一样,如果标准的J2EE安全性不能满足业务需求,则必须开发拦截器。
3、开发SpringAOP advice很方便,这些AOP Advice不仅仅POJO类,借助于Spring提供的ProxyFactoryBean,能够迅速的搭建Spring AOP Advice
Spring AOP的装备
1、before装备:在执行目标之前执行的装备
使用接口org.springframework.aop.MethodBeforeAdvice
源码如下:

public class LoggingBeforeAdvice implements MethodBeforeAdvice{
    protected static final Log log = LogFactory.getLog(LoggingBeforeAdvice.class);
    public void before(Method arg0,Object[] arg1,Object arg2){
        // before do something
    }
}
该方法在

调用目标操作之前调用,这很适用于那些有安全性要求的方法,即在调用目标操作之前检查客户身份。开发者还需要提供application.xml文件。

<beans>
<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
        <value>com.openv.spring.IHelloWorld</value>
    </property>
    <property name="target">
        <ref local="helloworldbeanTarget"/>
    </property>
    <property name="interceptorNames">
        <list>
            <value>loggingBeforeAdvisor</value>
        </list>
    </property>
</bean>
<bean id="helloworldbeanTarget" class="com.openv.spring.HelloWorld" />
<bean id="loggingBeforeAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
        <ref local="loggingBeforeAdvice" />
    </property>
    <property name="pattern">
        <value>.*</value>
    </property>
</bean>
<bean id="loggingBeforeAdvice" class="com.openv.spring.LoggingBeforeAdvice" />
</beans>

其中借助了RegexpMethodPointcutAdvisor类实现了对LoggingBeforeAdvice装备的集成,以完成pointcut和拦截器的定义。
2、Throws装备:如果目标操作在执行过程中抛出了异常,该装备会执行,可以采用Java捕捉异常而不用对异常信息或throwable进行造型
使用接口org.springframework.aop.ThrowsAdvice
对于处理事务或者特定业务需求很有帮助,源码如下:

public interface IHelloWorld{
    public String getContext(String helloworld) throws Exception;
}

public class HelloWorld implements IHelloWorld{
    protected static final Log log = LogFactory.getLog(HelloWorld.class);

    public String getContext(String helloworld) throws Exception{
        // do something
        throw new Exception();
    }
}

LoggingThrowsAdvice的装备代码如下:

public class LoggingThrowsAdvice implements ThrowsAdvice{
    protected Log log = LogFactory.getLog(LoggingThrowsAdvice.class);
    public void afterThrowing(Method method,Object[] args,Object target,Throwable subclass){
        // throw some Exception
    }
}

其实现了afterThrowing方法,当异常抛出时,该装备即被激活,具体的Spring配置文件如下:

<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
        <value>com.openv.spring.IHelloWorld</value>
    </property>
    <property name="target">
        <ref local="helloworldbeanTarget" />
    </property>
    <property name="interceptorNames">
        <list>
            <value>loggingThrowsAdvisor</value>
        </list>
    </property>
</bean>
<bean id="helloworldbeanTarget" class="com.openv.spring.HelloWorld" />
<bean id="loggingThrowsAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
        <ref local="loggingThrowsAdvice">
    </property>
    <property name="pattern">
        <value>.*</value>
    </property>
</bean>
<bean id="loggingThrowsAdvice" class="com.openv.spring.LoggingThrowsAdvice" />

应用抛出Exception后,LoggingThrowsAdvice的AfterThrowing即被激活

3、After装备:在执行目标之后执行的装备
After状态在执行密保操作之后执行装备中的afterReturnning方法。具体的LoggingAfterAdvice实现如下:

public class LoggingAfterAdvice implements AfterRuturningAdvice{
    protected static final Log log = LogFactory.getLog(LoggingAfterReturnningAdvice.class);
    public void afterReturnning(Object object,Method m,Object[] args,Object target) throws Throwable(
        // after do something
    )
}
配置文件:
<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
        <value>com.openv.spring.IHelloWorld</value>
    </property>
    <property name="target">
        <ref local="helloworldbeanTarget" />
    </property>
    <property name="interceptorNames">
        <list>
            <value>loggingAfterAdvisor</value>
        </list>
    </property>
</bean>

<bean id="helloworldbeanTarget" class="com.openv.spring.HelloWorld"/>
<bean id="loggingAfterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advisor">
        <ref local="loggingAfterAdvice" />
    </property>
    <property name="pattern">
        <value>.*</value>
    </property>
</bean>

<bean id="loggingAfterAdvice" class="com.openv.spring.LoggingAfterAdvice" />

使用接口org.springframework.aop.AfterReturningAdvice
对于代理Java接口的场景,Spring默认时是采用动态代理实现的,对于代理Java类的场景Spring采用动态字节码(byte-code)生成技术,比如使用了CGLIB库。
4、Around装备:在调用方法前后执行的装备。功能最强大,能够在目标操作执行前后实现特定的行为,使用灵活。
使用接口org.springframework.aop.MethodInterceptor
功能最强大,灵活性最好,能够在执行目标前后执行,这对一些需要做资源初始化和释放操作的应用特别有用,具体代码分析如下:

public class LoggingAroundAdvice implements MethodInterceptor{
    protected static final Log log = LogFactory.getLog(LoggingAroundAdvice.class);
    public Object invoke(MethodInvocation invocation) throws Throwable{
        log.info("before:The Invocation of getContent()");
        invocation.getArguments()[0] = "jader";
        invocation.proceed();
        log.info("after:The Inovation of getContent()");

        return null;
    }
}
配置文件如下:
<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean" >
    <property name="proxyInterfaces">
        <value>com.openv.spring.IHelloWorld</value>
    </property>
    <property name="target">
        <ref local="helloworldbeanTarget" />
    </property>
    <property name="interceptorNames">
        <list>
            <value>loggingAroundAdvisor</value>
        </list>
    </property>
</bean>
<bean id="loggingAroundAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
     <property name="advice">
        <ref local="loggingAroundAdvice">
     </property>
     <property name="pattern">
        <value>.*</value>
    </property>
</bean>
<bean id="loggingAroundAdvice" class="com.openv.spring.LoggingAroundAdvice" />

5、Introduction装备:能够为类新增方法,最复杂
这几种接口之间的关系:
这里写图片描述
ProxyFactoryBean
ProxyFactoryBean引入了间接层。通过名字或者id(helloworldbean)获得的引用对象并不是ProxyFactoryBean实例本身,而是ProxyFactoryBean中getObject方法实现返回的对象。其中getObject方法将创建AOP代理,并将目标对象包裹(wrapper)在其中。那么ProxyFactoryBean到底是什么?
ProxyFactoryBean实现了org.springframework.beans.factory.FactoryBean接口,本身也是JavaBean,下面是其类图:
这里写图片描述
主要有以下几个属性:
proxyInterfaces:接口构成字符串列表,即接口集合
proxyTargetClass:是否使用CGLIB代理目标类的标志位动态代理能够对接口指定,如果目标是类则无能无力,因此需要借助于CGLIB库,实现类的子类,从而起到代理类的作用。
interceptorNames:拦截器名构成的字符串列表,拦截器集合
target:执行目标类
SingleTon:单实例的标志位,每次调用ProxyFactoryBean的getObject方法时是返回同一个对象还是返回不同的对象。
下面看下具体的代码:

public class HelloClient{
    protected static final Log log = LogFactory.getLog(HelloClient.class);
    public static void main(String[] args){
        // 创建LoggingAroundAdvice装备
        Advice advice = new LoggingAroundAdvice();
        // 创建ProxyFactory,从而不需要借助Spring IOC容器提供反转功能
        ProxyFactory factory = new ProxyFactory(new HelloWorld());
        factory.addAdviced(advice);
        IHelloWorld hw = (IHelloWorld)factory.getProxy();
        log.info(hw.getContext("jader"));
    }
}

通过手工创建AOP代理能够摆脱Spring IOC容器的依赖。
Spring框架开发team推荐:借助于Spring IOC框架自动创建AOP代理,并将有关AOP代理的Java代理通过Spring配置文件配置。
FactoryBean在Spring框架起了很重要的作用,ProxyFactoryBean实现了FactoryBean接口,借助于ProxyFactoryBean能够实现各种业务需求,但要求去额外开发很多辅助业务操作,比如事务、数据库连接。
对象池
先研究下application.xml

// 借助于spring框架对commons pool的有效支持,能够实现对helloworldbeanTarget的有效池化
// 同时还能设置对象池的最大数量

<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
    <property name="targetBeanName">
        <value>helloworldbeanTarget</value>
    </property>
    <property name="maxSize">
        <value>25</value>
    </property>
</bean>

// 通过ProxyFactoryBean中指定targetSource属性,便能够使用到poolTargetSource提供的强大功能

<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource">
        <ref local="poolTargetSource" />
    </property>
    <property name="interceptorNames">
        <list>
            <value>loggingAroundAdvisor</value>
        </list>
    </property>
</bean>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值