上篇的例子,自动装配和自动检测Bean是使用注解的方式处理的,而面向切面编程是使用aop标签处理的,给我感觉就像中西医参合一样。
现在就来优化优化,全部使用注解的方式处理。
1、工程图:
2、Protecter的修改如下,Protecter声明了切点和通知,因此不需要在xml中配置切点和通知了。
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import com.test.demo.stolen.Peaces;
/**
* 守护者,是一个切面
* TODO Comment of Protecter
*
*/
@Component("protecter")
@Aspect
public class Protecter {
@Pointcut("execution(* com.test.demo.stolen.Stolen.stolens(String,com.test.demo.stolen.Peaces)) and args(name,peace)")
//stolens()是切点的一个名称,类似于xml配置时指定的id一样
public void stolens(){
}
@Before("stolens() && args(name,peace)")
public void before(String name,Peaces peace){
System.out.println("守护者在守护桃子"+peace.getName()+"...");
}
@After("stolens() && args(name,peace)")
public void after(String name,Peaces peace){
System.out.println("守护者发现猴子"+name+"在偷桃子"+peace.getName());
}
}
2、Stolen 接口,未做任何修改:
public interface Stolen {
/**
* 偷桃子
*
* @date 2014-4-1
*/
public void stolens(String name,Peaces peace);
}
3、Monkey实现Stolen接口,未做修改:
import org.springframework.stereotype.Component;
import com.test.demo.stolen.Peaces;
import com.test.demo.stolen.Stolen;
/**
* 猴子偷桃子
* TODO Comment of Monkey
*
*/
@Component("monkey")
public class Monkey implements Stolen{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void stolens(String name,Peaces peace){
System.out.println("猴子 "+name+" 正在偷桃子,桃子是:"+peace.getName()+" 大小:"+peace.getType());
this.name = name;
}
}
4、现在需要让Spring将Protecter应用成为一个切面。这个需要在Spring上下文中声明一个自动代理Bean。Spring中有个自动代理创建类:AnnotationAwareAspectJAutoProxyCreator.
这个类会代理一些Bean,这些Bean的方法需要与@AspectJ注解的Bean中所定义的切点相匹配。
在本例中,则表示:
AnnotationAwareAspectJAutoProxyCreator这个自动代理Bean,会找到使用@AspectJ注解的Bean。Protecter类使用了注解
@Aspect:@AspectJ注解
因此,Protecter类满足了使用@AspectJ注解的Bean这个要求,@AspectJ注解的Bean中所定义的切点相匹配,这表示会找到Protecter类中定义的切点:
与这个切点相匹配的则是com.test.demo.stolen.Stolen.stolens(name,peace) 这个方法了。
所以,本例中AnnotationAwareAspectJAutoProxyCreator类会自动代理实现了接口Stolen的Bean.即Monkey类。
Spring为了简化声明,Spring在aop命名空间中更为简洁的声明方式为:
<aop:aspectj-autoproxy />
beans.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context = "http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
default-autowire="byName">
<!-- 注解,自动装配bean -->
<context:annotation-config />
<!-- 自动检测Bean -->
<context:component-scan base-package="com.test"></context:component-scan>
<!-- 自动代理Bean -->
<aop:aspectj-autoproxy />
</beans>
测试类及运行结果:
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.test.demo.stolen.Peaces;
import com.test.demo.stolen.Stolen;
public class MonkeyStokenTest {
@Test
public void testStolen() {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Stolen m = (Stolen)ctx.getBean("monkey");
Peaces p = new Peaces();
p.setName("水蜜桃");
p.setType("BIG");
m.stolens("小小",p);
}
}