Spring入门


Spring入门

 为了能更好的理解先讲一些有的没的的东西:

    什么是Spring

 Spring是分层的JavaSE/EE full-stack(一站式) 轻量级开源框架
    分层
      SUN提供的EE的三层结构:web层、业务层、数据访问层(持久层/集成层)
      Struts2是web层基于MVC设计模式框架
      Hibernate是持久层的一个ORM的框架
    一站式
      Spring框架有对三层的每层解决方案
        web层:Spring MVC
        持久层:JDBC Template
        业务层:Spring的Bean管理 

 Spring的核心:

   控制反转意思就是说,当我们调用一个方法或者类时,不再有我们主动去创建这个类的对象,控制权交给别人(spring)。

  依赖注入意思就是说,spring主动创建被调用类的对象,然后把这个对象注入到我们自己的类中,使得我们可以使用它。

Spring优点
  方便解耦,简化开发
    Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理
  AOP编程的支持
    Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
  声明式事务的支持
    只需要通过配置就可以完成对事务的管理,而无需手动编程
  方便程序的测试
    Spring对Junit4支持,可以通过注解方便的测试Spring程序
  方便集成各种优秀框架
    Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
  降低JavaEE API的使用难度
    Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

前面讲的都是废话,下面开始进入最基础的:

Spring的入门的程序

(1)导包

   下载Spring的开发包

        下载最新的jar包地址:http://repo.spring.io/simple/libs-release-local/org/springframework/spring/
  
       spring-framework-4.3.7.RELEASE-dist.zip ---Spring开发包

 注意:
    spring-beans-4.3.7.RELEASE.jar     //这四个在spring开发包中文件搜索就可以找到
    spring-context-4.3.7.RELEASE.jar
    spring-core-4.3.7.RELEASE.jar
    spring-expression-4.3.7.RELEASE.jar
    开发的日志记录的包:                       //在apache下下载
      com.springsource.org.apache.commons.logging-1.1.1.jar --- 用于整合其他的日志的包(类似Hibernate中slf4j)
      com.springsource.org.apache.log4j-1.2.15.jar

(2)创建Spring的配置文件
    在src下创建一个applicationContext.xml
    引入XML的约束:在spring开发包中找到xsd-config.html.引入beans约束

<?xml version="1.0" encoding="UTF-8"?>
 

(3)创建接口:HelloServcie

public interface HelloServcie {
    
    public void sayHello();
}

(4)创建接口实现类:

1 public class HelloServiceImpl implements HelloServcie {
2     
3     public void sayHello() {
4         System.out.println("hello spring");
5     }
6 }

(5)配置applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
 

    
     
      
     
    
                    



(6)配置测试类

public class HelloTest { 
    public static void main(String[] args) {
        //传统写法 紧密耦合 
        HelloServiceImpl servcie =new HelloServiceImpl();
       //手动调用方法
       servcie.sayHello();
       
       //工厂+反射+配置文件  
       ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
       //通过工厂 和反射一级配置文件中的信息加载类对象
       HelloServcie helloServcie=(HelloServcie) applicationContext.getBean("helloServices");
       helloServcie.sayHello();       
    }
}
/*后台两次输出:hello spring
 */

这个例子非常简单,也主要是从这个例子说明spring的第一个优点那就是解耦合,这样更有利于后期的维护。

IOC装配Bean

(1)Spring框架Bean实例化的方式提供了三种方式实例化Bean
    构造方法实例化(默认无参数,用的最多)
    静态工厂实例化
    实例工厂实例化

下面先写这三种方法的applicationContext.xml配置文件:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 8        
 9         
10       
11      
12       
13      
14      
15      
16      
17         
Bean1类
public class Bean1 {
    
    //必须提供无参的构造函数  系统有默认无参的构造函数
}
Bean2类
public class Bean2 {
    private static Bean2 Bean2 = new Bean2();

    private Bean2() {
    }

    public static Bean2 createInstance() {
        return Bean2;
    }
}

 Bean3类

public class Bean3 {

}

Bean3Factory类

 1 public class Bean3Factory {
 2     
 3     private Bean3Factory(){
 4         
 5     }
 6       
 7     public Bean3 getInstance(){
 8         return new Bean3();
 9     }
10 }

测试类InstanceDemo

 1 import org.junit.Test;
 2 import org.springframework.context.ApplicationContext;
 3 import org.springframework.context.support.ClassPathXmlApplicationContext;
 4 
 5 public class InstanceDemo {
 6     
 7     //实例化工厂方法
 8     @Test
 9     public void demo3(){
10        //加载配置文件 创建工厂
11         ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
12         
13         Bean3 bean3 =(Bean3) applicationContext.getBean("bean3");
14         System.out.println(bean3);
15         
16     }
17     
18     //静态工厂方法
19     @Test
20     public void demo2(){
21        //加载配置文件 创建工厂
22         ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
23         
24         Bean2 bean2 =(Bean2) applicationContext.getBean("bean2");
25         System.out.println(bean2);
26         
27     }
28     //构造方法得到bean对象
29     @Test
30     public void demo1(){
31        //加载配置文件 创建工厂
32         ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
33         
34         Bean1 bean1 =(Bean1) applicationContext.getBean("bean1");
35         System.out.println(bean1);
36         
37     }
38 }
39 /*
40  * 这三个都得到类似于com.study.spring.b_instance.Bean1@7229c204 的内存地址
41  */

(2).Bean的其他配置:

     一般情况下,装配一个Bean时,通过指定一个id属性作为Bean的名称

         id 属性在IoC容器中必须是唯一的

         id 的命名要满足XML对ID属性命名规范 必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号

  如果Bean的名称中含有特殊字符,就需要使用name属性 例如:

        因为name属性可以相同,所以后出现Bean会覆盖之前出现的同名的Bean

   id和name的区别:

    id遵守XML约束的id的约束.id约束保证这个属性的值是唯一的,而且必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号 

        name没有这些要求

   如果bean标签上没有配置id,那么name可以作为id.

  Bean的scope属性

      
     
      

      * singleton :单例的.(默认的值.)

    * prototype :多例的.

     * request :web开发中.创建了一个对象,将这个对象存入request范围,request.setAttribute();

   * session :web开发中.创建了一个对象,将这个对象存入session范围,session.setAttribute();

   * globalSession :一般用于Porlet应用环境.指的是分布式开发.不是porlet环境,globalSession等同于session;

3.Bean属性的依赖注入

 前面已经知道如何获得对象,那我们接下来要知道如果给对象对象的属性赋值。

下面通过举例说明:

 Car 类  Car2类  CarInfo类  CollectionBean类  Employee类  TestDi测试类
上面这几个类都不是最主要的,我们主要是来看配置文件怎么写,这才是最关键的: 

applicationContext.xml
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 8     
 9     
10         
11      
12         
13             
14             
16              
17              
19              
20              
21              
22         
23         
24         
25       
26           
27           
28       
29       
30       
31           
32           
33       
34       
35       
36        
37       
38       
39       
40         
41       
42         
43             
44             
45         
46         
47          
48         
49             
50             
51             
52             
53              
54                  
55                      吃饭
56                      睡觉
57                      敲代码
58                  
59              
60              
61              
62              
63                  
64                      10
65                      20
66                      30
67                      40
68                      50
69                  
70              
71              
72              
73                  
74                      
75                      
76                      
77                  
78              
79              
80              
81              
82                  
83                      杭州余杭未来科技城
84                      200
85                  
86              
87         
88         
89         
90             
91             
92         
93         
94 

有关applicationContext.xml这个配置文件里的内容一定要看懂,我写的还是比较基础和全面的。

有关命名空间p的使用我这里在解释下:    

    p:<属性名>="xxx" 引入常量值

    p:<属性名>-ref="xxx" 引用其它Bean对象

IOC装配Bean(注解方式)

上面一遍文章Spring框架(2)---IOC装配Bean(xml配置方式)讲了通过xml来装配Bean,那么这篇来讲注解方式来讲装配Bean对象

  注解方式需要在原先的基础上重新配置环境:

(1)Component标签举例

1:导入架包:

这个包在spring开发包中就有,我测试了下,如果取消这个包,运行确实会报错:

org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [applicationContext.xml]; nested exception is 

 我只知道这个包是对于AOP起作用的,但我还是不知道这个包对于注解方面提供了怎样的帮助,大家如果知道,非常需要你的留言,谢谢!

第二个配置:applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
 
         
             
           
           
          
Component标签注入
@Component("helloService")  
//就相当于xml 文件中配置  id="helloService" class就是当前类
public class HelloService { 
}
HelloTest 测试类
 1 public class HelloTest {
 2     /*
 3      * 除了搭建环境和xml有点区别,其它方式一样
 4      */
 5     @Test
 6     public void demo1() {
 7         
 8         ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
 9         
10         HelloService helloService=(HelloService) applicationContext.getBean("helloService");
11         
12         System.out.println(helloService);
13     }
14     /*
15      * 输出一个内存地址:com.study.spring.a_beandefinition.HelloService@1895c4c
16      */
17 }

 上面是一个最基本的Component注入的简单例子:

 除了@Component外,Spring提供了3个功能基本和@Component等效的注解

    @Repository  用于对DAO实现类进行标注
    @Service        用于对Service实现类进行标注
    @Controller   用于对Controller实现类进行标注
     ***** 三个注解为了后续版本进行增强的

 (2)bean属性的注入:

  普通属性 

@Value(value="你好")
private String info;

 对象属性

  对象属性有两种方法,他们是对等的

    /*
     * @Autowired:自动装配默认使用类型注入.
    * @Qualifier("userDao"):按名称进行注入.
     */
  @Autowired
  @Qualifier("userDao")    
 private UserDao userDao;
@Resource(name="userDao")
private UserDao userDao;

Bean其他的属性的配置

    配置Bean初始化方法和销毁方法:init-method 和 destroy-method
    @PostConstruct 初始化
    @PreDestroy 销毁
  配置Bean的作用范围:@Scope("singleton")

整体的举例:

 1 @Service(value="userService")
 2 @Scope("singleton")
 3 public class UserService {
 4   @Value(value="你好")
 5   private String info;
 6 
 7   @Resource(name="userDao")
 8   private UserDao userDao;
 9 
10   public void sayHello(){
11     System.out.println("Hello Spring Annotation..."+info);
12   }
13 
14   @PostConstruct
15   public void setup(){
16     System.out.println("初始化...");
17   }
18 
19   @PreDestroy
20   public void teardown(){
21     System.out.println("销毁...");
22   }
23 }

Spring3.0提供使用Java类定义Bean信息的方法(用的很少)

 1 import org.springframework.context.annotation.Bean;
 2 import org.springframework.context.annotation.Configuration;
 3 
 4 /*
 5  * car和product领域对象类和相关属性我这里就不写了
 6  */
 7 @Configuration
 8 public class BeanConfig {
 9         
10     //就相当于得到了当前的car对象
11     @Bean(name="car")
12     public Car initCar(){
13         Car car =new Car();
14         car.setName("法拉利");
15         car.setPrice(6000000);
16         return car;
17     }
18     //同样就相当于得到了product对象
19     @Bean(name="product")
20     public Product showProduct(){
21         Product product =new Product();
22         product.setPname("空调");
23         product.setPnum(200);
24         return product;
25     }
26 }

测试类

 1 import org.junit.Test;
 2 import org.springframework.context.ApplicationContext;
 3 import org.springframework.context.support.ClassPathXmlApplicationContext;
 4 
 5 import com.study.spring.b_di.Car;
 6 import com.study.spring.b_di.Product;
 7 import com.study.spring.b_di.ScopeBean;
 8 import com.study.spring.c_di.CustomerService;
 9 
10 public class SpringTest {
11    
12     //测试
13     @Test
14     public void demo2(){
15         ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
16         
17         Car car =(Car) applicationContext.getBean("car");
18         System.out.println(car);
19         
20         Product product =(Product) applicationContext.getBean("product");
21         System.out.println(product);
22      /*
23       * 输出结果:  
24       *  Car [name=法拉利, price=6000000.0]
25       *  Product [pname=空调, pnum=200]
26       */
27        //说明已经获得了方法返回的两个对象 
28     }
29 }

(3)实际开发中使用XML还是注解?

  XML:有利于bean管理
   注解:注入属性的时候比较方便
   两种方式结合:一般使用XML注册Bean,使用注解进行属性的注入

最后我找来一张图,用这张图来结尾本篇文章

有不足之处,欢迎大家指点,谢谢!

AOP讲解铺垫

     不得不说,刚开始去理解这个Aop是有点难理解的,主要还是新的概念比较多,对于初学者一下子不一定马上能够快速吸收,所以我先对什么事Aop做一个解释:

    首先说明:本文不是自己所写,是转载于:http://www.cnblogs.com/zs234/p/3267623.html    非常感谢这位作者出这么好的文章,我只是搬运工。

  上次的博文Spring框架(3)---IOC装配Bean(注解方式)主要讲有关bean方面的知识,接下来我们继续讲解另一个核心AOP(Aspect Oriented Programming),即面向切面编程。

1、OOP回顾

       在介绍AOP之前先来回顾一下大家都比较熟悉的OOP(Object Oriented Programming)。OOP主要是为了实现编程的重用性、灵活性和扩展性。它的几个特征分别是继承、封装、多态和抽象。OOP重点体现在编程架构,强调的是类之间的层次关系。

2、OOP缺陷

       为了更好的说明OOP的概念,我们接下来讲一个OOP的实例,重点分析OOP存在哪些缺陷,以便更好的理解AOP的相关内容。

       先看如下的一张图:

       上面这张图有三个类:Dog,Cat和Duck,他们都有一个方法run。按照OOP的设计理念,我们很容易就会想到抽象出一个Animal父类,同时让这三个子类继承Animal父类。这样的设计可以用如下的图示表示:

       在OOP思想中,我们会使用大量的类似上图的编程方式,对类进行抽象、继承、封装和多态来实现编程的重用性、灵活性和扩展性。但是这样的编程仍然有一定的局限性,有时候,OOP并不能很好解决我们再实际开发中遇到的问题。为了说明这个问题,看下面的图示:

       看到上面的图,我们暂时还不能发现有什么问题。为了大家便于理解,接下来我来给大家讲解一下上面类图的实现过程。描述如下:马戏团有一条表演的小狗,这条小狗可以跑和跳,但是它完成跑和跳两个动作之前必须是在接到驯兽师发出的命令后,同时完成跑和跳的动作之后,驯兽师会给与响应的奖励,比如一块肉。

       了解了实现过程之后,我们在来看一下具体的代码。 

   public class Dog {   
        public void run() {
            System.out.println("驯兽师发出命令!")
            System.out.println("小狗开始跑!");
            System.out.pringln("驯兽师给与奖励");
        }  
        public void jump() {
            System.out.println("驯兽师发出命令!")
            System.out.println("小狗开始跳!");
            System.out.pringln("驯兽师给与奖励");
        }
    }
    仔细看上面的代码,我们可以看出在run方法和jump方法中,存在一些相同的内容(驯兽师发出命令和给与奖励),这些内容并不能完全进行抽象,即不能按照OOP编程思想进行处理。类似这样的情况同样会出现在我们编程中的很多地方,例如:日志记录、性能统计、安全控制、事务处理、异常处理等等。但是这样的情况该如何解决呢?这就引入了AOP编程思想。

3、AOP简介

       AOP为Aspect Oriented Programming的缩写,即面向切面编程(也叫面向方面),是一种可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

4、AOP实现实例

      为了大家更好的理解AOP如何实现,接下来我们优化一下上述代码。

      首先是Dog类

public interface Animal {
        public void run();
        public void jump();
    }
    
    public class Dog implements Animal{
        public void run(){
            System.out.println("小狗开始跑!");
        }    
        public void jump(){
            System.out.println("小狗开始跳!");
        }        
    }

     对比之前的代码我们可以明显看出,我们将关于驯兽师的相关内容从run和jump中进行了抽取,接下来,我们如何在程序运行中将关于驯兽师的动作加入到程序中呢?这就是我们这次用到的AOP实现的核心技术动态代理(Dynamic Proxy)。具体代码如下:

 public class MyProxy  implements InvocationHandler{
        private Object targetObject;        
        public Object createProxyInstance(Object targetObject) {
            this.targetObject = targetObject;
            return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), 
                                   targetObject.getClass().getInterfaces(), 
                                   this);
        }
        
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            command();        
            Object ret = method.invoke(targetObject, args);
            award();
            return ret;
        }
        
        private void command() {
            System.out.println("驯兽师发出命令!");
        }
        
        private void award(){
            System.out.println("驯兽师给与奖励!");
        }
    }
  上述代码实现完成之后,我们改如何调用呢?参考代码如下:
    public class Client {
        public static void main(String[] args) {
            MyProxy hander = new MyProxy();
            Animal dog = (Animal)hander.createProxyInstance(new Dog());
            dog.run();
            dog.jump();
        }
    }
  执行结果如下:

  从这个例子我们可以看出,我们并没有在方法了写 两次驯兽师发出命令!,但运行中却可以有两次,这是不是提高代码的效率了呢。

       关于AOP编程的实例演示就完成了,接下来重新回顾一下AOP与OOP的相关概念。

5、AOP与OOP的关系

       OOP针对业务处理过程的实体(Dog、Cat、Duck)及其属性和行为(run)进行抽象封装,以获得更加清晰高效的逻辑单元划分。而AOP则是针对业务处理过程中(run或jump)的切面(command和award)进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。

AspectJ实现AOP

   上一篇文章Spring框架(4)---AOP讲解铺垫,讲了一些基础AOP理解性的东西,那么这篇文章真正开始讲解AOP

    通过AspectJ实现AOP要比普通的实现Aop要方便的多,所以第五篇文章有关SpringAOP我暂且不写,后面整理好了再补充上;

   那我们首先还是讲一些有的没的的东西:

什么是Spring的AspectJ的AOP

      AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
  Spring2.0以后新增了对AspectJ切点表达式支持,@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
  新版本Spring框架,建议使用AspectJ方式来开发AOP

那我们先来一个小案例,还是以前面狗的案例举例:

1.导入相关架包

在原来的基础上导入下面四个架包:

  • spring-aop-4.2.0.RELEASE.jar
  • com.springsource.org.aopalliance-1.0.0.jar
  • spring-aspects-4.2.0.RELEASE.jar
  • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

 2.编写配置文件applicationContext.xml    导入aop的命名空间

<?xml version="1.0" encoding="UTF-8"?>
 
         
         
          
          
        
        



 3.编写代理对象

 1 public class Dog {
 2 
 3     public void run() {
 4         System.out.println("狗会跑");
 5     }
 6 
 7     public void jump() {
 8 
 9         System.out.println("狗会跳");
10 
11     }
12 
13     public void eat() {
14 
15         System.out.println("狗能吃");
16     }
17 }

4)编写切面类

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//@Aspect声明当前类是一个切面
@Aspect     
public class MyAspectJ {
    //@Before代表在执行方法之前执行增强代码
    @Before("execution(* com.study.dog.Dog.*(..))")
    public void before1() {
        System.out.println("饲养员叫你你猜能动");
    }

}

5编写配置文件 

<?xml version="1.0" encoding="UTF-8"?>
 
         
         
          
          
        
        
        
        
          
           
         
          
       
        

6.编写测试类

 1 import org.junit.Test;
 2 import org.junit.runner.RunWith;
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.beans.factory.annotation.Qualifier;
 5 import org.springframework.test.context.ContextConfiguration;
 6 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 7 
 8 //完成配置文件的加载
 9 @RunWith(SpringJUnit4ClassRunner.class)
10 @ContextConfiguration(locations="classpath:applicationContext.xml")
11 public class AspectJTest {
12     // 得到dog对象
13     @Autowired
14     @Qualifier("Dog")
15     private Dog dog;
16 
17     @Test
18     public void Demo1() {
19         dog.eat();
20         dog.run();
21         dog.jump();
22     }
23     /*
24      * 输出结果:
25      *    饲养员叫你你猜能动
26      *    狗能吃
27      *    饲养员叫你你猜能动
28      *    狗会跑
29      *    饲养员叫你你猜能动
30      *    狗会跳
31      */
32 }

 总结:上面是一个最简单的AspectJ的AOP,我们这样就可以通过输入一个”饲养员叫你你猜能动",就可以在多个方法中存在,在以后开发非常需要

那么下来来说一些非常重要的干货!

 AspectJ表达式:
    语法:execution(表达式) 通过execution函数,可以定义切点的方法切入

      execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)      

         例如

               execution(public * *(..))                             匹配所有类public方法

               execution(* cn.study.dao..*(..))                  匹配指定包下所有类方法,不包含子包

     execution(* cn.study.dao..*(..))                  ..*表示包、子孙包下所有类

     execution(* cn.study.service.UserService.*(..))  匹配指定类所有方法

     execution(* cn.study.dao.GenericDAO+.*(..))   匹配实现特定接口所有类方法

     execution(* save*(..))                                     匹配所有save开头的方法

    AspectJ增强
    @Before 前置通知,相当于BeforeAdvice
    @AfterReturning 后置通知,相当于AfterReturningAdvice
    @Around 环绕通知,相当于MethodInterceptor
    @AfterThrowing抛出通知,相当于ThrowAdvice
    @After 最终final通知,不管是否异常,该通知都会执行
    @DeclareParents 引介通知,相当于IntroductionInterceptor (不要求掌握)

那现在我们通过上面的列子,来全面贯彻上面的干货!

对上面MyAspectJ的进行全面增强:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
//@Aspect声明当前类是一个切面
@Aspect     
public class MyAspectJ {
   
     //@Before代表在执行方法之前执行增强代码
     @Before("execution(* com.study.dog.Dog.run(..))")
        public void before(JoinPoint joinPoint){
            System.out.println("前置增强...."+joinPoint);
        }  
     //后置通知
      @AfterReturning (value="execution(* com.study.dog.Dog.jump(..))",returning="returnVal")
        public void afterReturin(Object returnVal){
            System.out.println("后置增强....方法的返回值:"+returnVal);
        }  
      //环绕通知
        @Around(value="MyAspectJ.myPointcut()")
        public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
            System.out.println("环绕前增强....");
            Object obj = proceedingJoinPoint.proceed();
            System.out.println("环绕后增强....");
            return obj;
        } 
        //抛出通知
        @AfterThrowing(value="MyAspectJ.myPointcut()",throwing="e")
        public void afterThrowing(Throwable e){
            System.out.println("不好了 出异常了!!!"+e.getMessage());
        } 
        
        //最终final通知,不管是否异常,该通知都会执行
        @After("MyAspectJ.myPointcut()")
        public void after(){
            System.out.println("最终通知...");
        } 
      //切点的定义
        @Pointcut("execution(* com.study.dog.Dog.eat(..))")
        private void myPointcut(){}
}

编写测试类AspectJTest   和上面一点不变 

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

//完成配置文件的加载
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class AspectJTest {
    // 得到dog对象
    @Autowired
    @Qualifier("Dog")
    private Dog dog;

    @Test
    public void Demo1() {
        dog.eat();
        dog.run();
        dog.jump();
    }

}

运行结果:

通过这个例子,相信大家对于AspectJ的AOP有了一定的了解了。

最后补充一个面试题:

     Advisor和Aspect的区别?
        Advisor:Spring传统意义上的切面:支持一个切点和一个通知的组合.
        Aspect:可以支持多个切点和多个通知的组合.