利用例子来理解spring的面向切面编程

最近学习了spring的面向切面编程,在网上看到猴子偷桃的例子,觉得这种方式学习比书本上讲解有趣多了,也便于理解。现在就来基于猴子偷桃写个基本的例子。

maven工程:

 

1、猴子偷桃子,这里就有两个类出现,一类是猴子,一类是桃子。如果以后需要扩展,来个狼偷羊,怎么办呢?因此为了扩展,可以声明接口Stolen,表现偷的行为。

Stolen接口:

 

package com.test.demo.stolen;

public interface Stolen {
    /**
     * 偷桃子
     * 
     * @date 2014-4-1
     
*/
    public void stolens(String name,Peaces peace);
}

 

猴子需要实现这个Stolen接口,表示猴子具有偷的行为,Monkey类:

 

package com.test.demo.stolenImpl;

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;
    }
}
View Code

 

 

 2、猴子偷的桃子具有哪些属性呢?它的大小?品种?因此声明桃子的对象Peace(桃子的英文为peach,写错了,囧~):

 

package com.test.demo.stolen;

/**
 * 桃子
 * TODO Comment of Peaces
 *
 
*/
public class Peaces {

    /**
     * 品种
     
*/
    private String name;
    /**
     * 大小
     
*/
    private String type;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}
View Code

3、守护者来了,需要保护桃子不被偷,Protecter类:

package com.test.demo.protect;

import org.springframework.stereotype.Component;

import com.test.demo.stolen.Peaces;

/**
 * 守护者,是一个切面
 * TODO Comment of Protecter
 *
 
*/
@Component("protecter")
public class Protecter {
    

    public void before(String name,Peaces peace){
        System.out.println("守护者在守护桃子"+peace.getName()+"...");
    }
    
    public void after(String name,Peaces peace){
        System.out.println("守护者发现猴子"+name+"在偷桃子"+peace.getName());
    }
}

 4、现在需要在beans.xml配置了:

<?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: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>
        
    <aop:config>
        <!--切点:偷的行为  -->
        <aop:pointcut expression="execution(* com.test.demo.stolen.Stolen.stolens(String,com.test.demo.stolen.Peaces)) and args(name,peace)" id="stolen"/>
        <!--切面: 守护者 -->
        <aop:aspect ref="protecter">
            <!-- 偷之前,守护者的行为 -->
            <aop:before method="before" pointcut-ref="stolen" />
            <!-- 偷之后,守护者的行为 -->
            <aop:after method="after" pointcut-ref="stolen"/>
        </aop:aspect>
    </aop:config>
</beans>

在运行时我遇到了以下两个问题:

1)、在声明切点stolen时,切点表达式中传递了参数name和peace,Peaces的类型此时需要连同包名全部声明,否则会报错:

 

warning no match for this type name:peace Xlint:invalidAbsoluteTypeName
2)、Protecter类中的before和after方法,都要有参数传递,即before(String name,Peaces peace)、after(String name,Peaces peace)。

 

如果参数不完整,也会报错:

 

warning no match for this type name:peace Xlint:invalidAbsoluteTypeName  或

 

warning no match for this type name:name Xlint:invalidAbsoluteTypeName
 

 

 

5、写个测试类,来测试猴子偷桃:

package com.test.demo;

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);
    }
}

 控制台打印出的内容为:

 

 

 

 至此,猴子偷桃就结束了。但是现在是有人来偷桃子,怎么处理呀?诶,之前为了方便扩展,声明了个接口Stolen,既然是人来偷桃子,那我声明个Person类,并且让Person实现Stolen接口不就行了:

package com.test.demo.stolenImpl;

import org.springframework.stereotype.Component;

import com.test.demo.stolen.Peaces;
import com.test.demo.stolen.Stolen;

@Component("person")
public class Person implements Stolen{

    public void stolens(String name,Peaces peace){
        System.out.println("这个人 "+name+" 正在偷桃子,桃子是:"+peace.getName()+" 大小:"+peace.getType());
    }
}

 写个测试类来测试下:

package com.test.demo;

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

import com.test.demo.stolen.Peaces;
import com.test.demo.stolen.Stolen;

public class PersonStolenTest {

    @Test
    public void testStolen() {
     ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
         Stolen m = (Stolen)ctx.getBean("person");
         Peaces p = new Peaces();
         p.setName("猕猴桃");
         p.setType("SMALL");
         m.stolens("小明",p);
    }
}

 打印结果:

 

 

 

--------------------------------------分割线-------------------------------------------

又有个疑问,既然可扩展,那偷的不一定是桃子,也许是别的,这个怎么处理?

这时就要修改代码了,可以先声明一个接口,如Fruits,提取一些共有的属性。

当偷的是桃子,则声明类Peach,实现Fruits 接口,并可以创建桃子的一些私有属性。

其他也如是。


 

附带pom.xml中的声明:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <artifactId>trainingTest</artifactId>
    <groupId>com.test.training</groupId>
    <version>0.0.1-SNAPSHOT</version>
    <relativePath>..</relativePath>
  </parent>
  <artifactId>AnnTest</artifactId>
  <packaging>war</packaging>
  
  <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
             <artifactId>spring-context</artifactId>
            <version>3.2.3.RELEASE</version>
          </dependency>
         <dependency>  
           <groupId>org.springframework</groupId>  
           <artifactId>spring-core</artifactId>  
           <version>3.2.3.RELEASE</version>  
       </dependency>  
       
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
        </dependency>
  </dependencies>
</project>

 如果没有aspectjweaver-1.6.8.jar包,会报缺少这个jar包哦~

 

posted @ 2014-04-02 10:05  爱生活者wmmang  Views(597)  Comments(0Edit  收藏  举报