spring-aop

来源:互联网 发布:微信购物商城源码 编辑:程序博客网 时间:2024/06/07 16:57

spring的AOP里面的术语主要有:通知(Advice),连接点(Joinpoint),切入点(Pointcut),切面(Aspect),引入(Instroduction),目标(target),代理(Proxy),织入(Weaving)

主要还是以例子形式:

1,创建一个POJO------------Audience

 主要是里面定义了一些待会儿要用到的方法

package com.spring.aop;


public class Audience {
   public Audience() {}

   public void takeSeats(){
  System.out.println("The audience is taking their seats");
   }
   public void turnOffCellPhones() {
  System.out.println("The audience is turning off their cellphones");
   }
   public void applaud(){
  System.out.println("CLAP CLAP CLAP CLAP CLAP");
   }
   public void demandRefund(){
  System.out.println("Boo!  We want our money back");
   }
}

利用如下XML可以把它装配为Spring的bean

<bean id="audience" class="com.spring.aop.Audience" />


2、创建通知------------------有两种方式:1、实现接口 MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice

                                                                2、实现接口MethodInterceptor

第一种方式:

package com.spring.aop;

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;


public class AudienceAdivce implements MethodBeforeAdvice, AfterReturningAdvice,
        ThrowsAdvice{


@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
audience.takeSeats();
audience.turnOffCellPhones();

}


@Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
audience.applaud();

}


    public void afterThrowing(Throwable throwable){
    audience.demandRefund();
    }

private Audience audience;


public void setAudience(Audience audience) {
this.audience = audience;
}
}

在这里方法afterThrowing(Throwable throwable)是要自己添加的没有覆盖的方法

利用如下XML可以把它装配为Spring的bean

<bean id="audienceAdivce" class="com.spring.aop.AudienceAdivce">
<property name="audience" ref="audience" />
</bean>


第二种方法代码略


3、接下来就是要定义切点和通知者------正则表达式切点和AspectJ切点

利用如下XML可以把它装配为Spring的bean

声明正则表达式切点

<bean id="audienceAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="audienceAdivce"></property>
<property name="pattern" value=".*perform"></property>
</bean>

定义AspectJ切点

 <bean id="audienceAdvisor"
class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<property name="advice" ref="audienceAdivce"></property>
<property name="expression" value="execution(* *.*perform(..))"></property>
</bean>

很奇怪perform()方法不知道是哪里来的,对,我们确实少了真正的使用者

4、称为“使用者”的定义

接口:

package com.spring.aop;

public interface PerformService {
public void perform();
}

实现:

package com.spring.aop;

public class PerformServiceImpl implements PerformService {

@Override
public void perform() {
System.out.println("performer is dancing");
}
}

利用如下XML可以把它装配为Spring的bean

<bean id="performService" class="com.spring.aop.PerformServiceImpl" />


这样一个最基本的aop应用完成了

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

当然我们一般使用的都是用工厂bean来进行切入点与通知揉合的

5、使用ProxyFactoryBean


利用如下XML可以把它装配为Spring的bean

<bean id="per" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="performService" />
<property name="proxyInterfaces" value="com.spring.aop.PerformService"></property>
<property name="interceptorNames">
<list>
<value>audienceAdivce</value>
</list>
</property>
</bean>

细心的朋友肯定会发现

<property name="interceptorNames">
<list>
<value>audienceAdivce</value>
</list>
</property>

说明可以配置多个通知


6、测试

package com.spring.aop;

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

public class Main {

public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"classpath*:applicationContext.xml");
        //System.out.println(context);
PerformService performService = (PerformService) context.getBean("audience");
        performService.perform();
}
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

当然看到这里有一个问题是多个使用者对同一个通知的代理仅仅是bean的id不一样,这样就会使得XML文件显的很冗余,当然这肯定是有解决的办法,就是应用抽象的ProxyFactoryBean

抽象bean的详细可以参考bean的装配文章,

利用如下XML可以把它装配为Spring的bean

<bean id="perBase" class="org.springframework.aop.framework.ProxyFactoryBean" 

                                         abstract="true">

<property name="target" ref="performService" />
<property name="proxyInterfaces" value="com.spring.aop.PerformService"></property>
<property name="interceptorNames">
<list>
<value>audienceAdivce</value>
</list>
</property>
</bean>


上面定义的是一个抽象的bean,接下来就是要从上面的bean进行扩展:

<bean id="per1" parent="perbase">
        <property name="target" ref="performService1"/>
</bean>


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

上面的应用已经节省了很多的代码,但是每个使用者还是要定义两个bean:目标bean和代理bean,下面就是使用自动代理了 ,让Spring自动为每个具有与通知者切点相匹配方法的bean创建代理

只需要在下面的定义AspectJ切点的基础上声明一个bean

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

---------------------------------------------------------------------------------------------------------------------------------------------------

定义AspectJ切点

 <bean id="audienceAdvisor"
class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<property name="advice" ref="audienceAdivce"></property>
<property name="expression" value="execution(* *.*perform(..))"></property>
</bean>


最后还有就是一种定义纯粹的POJO切面(暂略)