Spring的AOP

AOP(aspect oriented <['orɪɛntɪd]导向> Programming,面向切面编程)

AOP把一个业务流程分成几部分,例如权限检查、事务处理、日志记录,每个部分独立处理,然后把它们组装成完整的业务流程

 

aop小例子:

package com.aop;

public interface IAopService {
    public void withAop() throws Exception;
    public void withoutAop() throws Exception;
}

package com.aop;

import javax.security.auth.login.AccountException;

public class AopServiceImpl implements IAopService {

    private String name;
    public void withAop() throws Exception {
        System.out.println("有AOP的函数运行。name:"+name);
        if(name.trim().length()==0){
            throw new AccountException("name属性不能为空");
        }
    }

    public void withoutAop() throws Exception {
        System.out.println("没有AOP的函数运行。");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}


package com.aop;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class MethodAfterInterceptor implements AfterReturningAdvice{

    public void afterReturning(Object value, Method method, Object[] arg2,
            Object instance) throws Throwable {
        System.out.println("方法"+method.getName()+"运行完毕,返回值为:"+value);
    }

}

package com.aop;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class MethodBeforeInterceptor implements MethodBeforeAdvice{

    public void before(Method method, Object[] arg, Object instance)
            throws Throwable {
        System.out.println("即将要执行的方法:"+method.getName());
        if(instance instanceof AopServiceImpl){
            String name=((AopServiceImpl)instance).getName();
            if(name==null){
                throw new NullPointerException("name属性不能为null");
            }
        }
    }

}


package com.aop;

import java.lang.reflect.Method;

import javax.security.auth.login.AccountException;

import org.springframework.aop.ThrowsAdvice;

public class ThrowsInterceptor implements ThrowsAdvice{
    public void afterThrowing(Method method,Object[] args,Object instance,AccountException ex) throws Throwable{
        System.out.println("方法"+method.getName()+"抛出了异常: "+ex);
    }
    public void afterThrowing(NullPointerException ex) throws Throwable{
        System.out.println("抛出了异常: "+ex);
    }
}


package com.Test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.aop.IAopService;

public class AopRun {
    @Test
    public static void main(String[]args) throws Exception{
        ApplicationContext conte=new ClassPathXmlApplicationContext("applicationContext.xml");
        IAopService hello=(IAopService)conte.getBean("aopService");
        hello.withAop();
        
    }

}


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

    
    <bean id="aopMethodBeforeInterceptor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="advice">
            <bean class="com.aop.MethodBeforeInterceptor"></bean>
        </property>
        <property name="mappedName" value="withAop"></property>
    </bean>
    
    <bean id="aopMethodAfterInterceptor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="advice">
            <bean class="com.aop.MethodAfterInterceptor">
            </bean>
        </property>
        <property name="mappedName" value="withAop"></property>
    </bean>
    <bean id="aopThrowsInterceptor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="advice">
            <bean class="com.aop.ThrowsInterceptor"></bean>
        </property>
        <property name="mappedName" value="withAop"></property>
    </bean>
    
    <!--  Service对象,安装到ProxyFactoryBean对象中 -->
    <bean id="aopService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="interceptorNames">
            <list>
                <value>aopMethodBeforeInterceptor</value>
                <value>aopMethodAfterInterceptor</value>
                <value>aopThrowsInterceptor</value>
            </list>
        </property>
        <property name="target">
            <bean class="com.aop.AopServiceImpl">
                <property name="name" value="sss"></property>
            </bean>
        </property>
    </bean>
</beans>
View Code

 

拦截器与Filter的区别

Spring的拦截器与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,能实现权限检查、日志记录等等。不同的是:

1、使用范围不同:Filter是Servlet规范规定的,只能用于Web程序中。而拦截器既可以用于Web程序,也可以用于Application、Swing程序中

2、规范不同:Filter实在Servlet规范中定义的,是Servlet容器支持的。而拦截器是Spring容器内的,是Spring框架支持的。

3、使用的资源不同:同其他的代码块一样,拦截器也是一个Spring组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如Service对象、数据源、事务管理等,通过IoC注入到拦截器即可,Filter不能

4、深度不同:Filter只在Servlet前后起作用。而拦截器能够深入到方法前后、异常抛出前后等等,因此拦截器具有更大的弹性。所以在Spring构架的程序中,要优先使用拦截器。

 

AOP的相关概念

1、切面 Aspect:在本例中,方法withAop()、withoutAop()中都有一些代码。虽然只是一些输出语句,但是在真实的程序中这里应该是一些有意义的代码(如读写数据库、权限检查、异常情况记录等等)。这些代码可以看做事AOP中的切面(Aspect)。可以将切面理解成模块

2、通知Advisor:本例的三个拦截器都是实现自某个Advise接口。从类名上看就知道三个拦截器就是AOP中的通知(Adcisor)。一旦Spring复合条件,就会派发出通知。与生活中的通知不同的是,Spring的通知是带有执行代码的,能实现某种功能。

3、切入点Pointcut:在配置拦截器的时候,XML只配置了withAop()方法使用拦截器,而withoutAop()方法没有配置拦截器。这种配置时借助于org.springframework.aop.support.NameMathMethodPointcutAdvisor完成的。从类名称上看,这是一个切入点(Pointcut)。该类对象能够配置哪些方法使用拦截器,从哪个地方切进去。配置的时候可以使用通配符。该类名上也带有Adcisor是因为它是用通知(Advisor)实现的

简单地说,切入点负责往什么地方插入代码,而通知负责插入什么代码

4、切入点配置方式:Spring提供灵活的切入点配置方式,例如使用正则表达式。

<bean id="aopMethodAfterInterceptor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <bean class="com.aop.MethodAfterInterceptor">
            </bean>
        </property>
        <property name="patterns">
            <list>
                <value>.*withAop</value>
                <value>.*like.*</value>
            </list>
        </property>
    </bean>


package com.Test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.aop.IAopService;

public class AopRun {
    @Test
    public static void main(String[]args) throws Exception{
        ApplicationContext conte=new ClassPathXmlApplicationContext("applicationContext.xml");
        IAopService hello=(IAopService)conte.getBean("aopService");
        hello.withAop();
        hello.youlike();
        
    }
    
    public static void slikeme(){
        System.out.println("这是slikeme方法");
    }

}

其他不是很需要讲解的地方加了slikeme方法
View Code

注意:正则有点怪。(好像前面必须是.*)

 

AOP的代理模式

代理模式是Spring中常用的设计模式。Spring提供了几个常用的代理类,例如普通的代理类、事务处理类等等。

1、ProxyFactoryBean代理工厂对象

org.springframework.aop.framework.ProxyFactory.这是spring内置的代理类,引入了一个中间层,能够创建不同类型的对象。利用它可以实现任何形式的AOP

2、TransactionProxyFactoryBean事务代理工厂对象

TransactionProxyFactoryBean,是ProxyFactoryBean的子类,常用在数据库编程上。Spring、利用TransactionProxyFactoryBean对事务进行管理,在指定方法前利用AOP连接数据库并开启事务,然后在指定的方法返回后利用AOP提交事务并断开数据库。

<bean id=:petStoreTarget" class="......" ><!--代码实例-->
    <property name="accountDao">
        <ref bean="accountDao" />
    <property>  <!--设置DAO引用-->
</bean>
<bean id="petStore" class="org.springframework.interceptor.TransactionProxyFactoryBean"><!--安装事务管理bean-->
     <property name="transactionManager" ref="transactionManager" /><!--事务管理Bean-->
    <property name="target" ref="petStoreTaeget" /><!--安装到该bean-->
    <property name="transactionAttributes"><!--方法名配置-->
        <props>
             <prop key="insert">PROPAGATION_REQUIRED</prop>
             <prop key="update*">PROPAGATION_REQUIRED</prop>
             <prop key="*">PROPAGATION_REQUIRED,readoOnly</prop>
        </props>
    </property>
</beans>

 注意:使用spring的aop的时候将ProxyFactoryBean只能转化成为接口类型。而不是它的实现类。

posted @ 2016-05-06 17:32  guodaxia  阅读(269)  评论(0编辑  收藏  举报