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切面(暂略)