Spring 之 AOP

面向方面的编程,即 AOP,是一种编程技术,它允许程序员对横切关注点或横切典型的职责分界线的行为(例如日志和事务管理)进行模块化。AOP 的核心构造是方面,

它将那些影响多个类的行为封装到可重用的模块中。

通常情况下,对于AOP,我们有两种方式来实现。

  使用DynamicProxy实现AOP

  下面是一个简单的示例,首先定义业务对象:

 1 public interface UserDao {
 2
 3     void save();
 4 }
 5
 6 public class UserDaoImpl implements UserDao
 7 {
 8     private String name;
 9
10     public void save() {
11         System.out.println("save() is called for " + name);
12     }
13
14     public void setName(String name) {
15         this.name = name;
16     }
17
18     public String getName() {
19         return name;
20     }
21 }

  下面是一个实现了InvocationHandler的类:

 1 public class ProxyFactory implements InvocationHandler
 2 {
 3     private Object target;
 4
 5     public Object createUserDao(Object target)
 6     {
 7         this.target = target;
 8         return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),
 9                 this.target.getClass().getInterfaces(), this);
10     }
11
12     public Object invoke(Object proxy, Method method, Object[] args)
13             throws Throwable {
14
15         UserDaoImpl userDao = (UserDaoImpl)target;
16         Object result = null;
17         if(userDao.getName() != null)
18         {
19             result = method.invoke(target, args);
20         }
21         else
22         {
23             System.out.println("The name is null.");
24         }
25         return result;
26     }
27 }

  接下来是测试代码:

1 private static void test1()
2 {
3     ProxyFactory pf = new ProxyFactory();
4     UserDao userDao = (UserDao)pf.createUserDao(new UserDaoImpl());
5     userDao.save();
6 }

  执行结果如下:

The name is null.

  这是因为userDao的类型是UserDao,它是一个接口,并没有定义name字段,因此name=null。

  使用Cglib实现AOP

  同样是上面的需求,我们假设并没有继承的接口,这我们可以使用cglib来实现。

  首先我们重新定义一个UserDaoImpl2,它不会实现任何接口:

 1 public class UserDaoImpl2
 2 {
 3     private String name;
 4
 5     public void save() throws InterruptedException {
 6         Thread.sleep(3000);
 7         System.out.println("save() is called for " + name);
 8     }
 9
10     public void setName(String name) {
11         this.name = name;
12     }
13
14     public String getName() {
15         return name;
16     }
17
18     public void raiseException()
19     {
20         throw new RuntimeException("This is test.");
21     }
22 }

  然后是创建CglibFactory:

 1 public class CglibFactory implements MethodInterceptor
 2 {
 3     private Object target;
 4     public Object createUserDao(Object target)
 5     {
 6         this.target = target;
 7         Enhancer enhancer = new Enhancer();
 8         enhancer.setSuperclass(target.getClass());
 9         enhancer.setCallback(this);
10         return enhancer.create();
11     }
12
13     public Object intercept(Object proxy, Method method, Object[] args,
14             MethodProxy methodProxy) throws Throwable {
15         UserDaoImpl2 userDao = (UserDaoImpl2)target;
16         if (userDao.getName() != null)
17         {
18             return method.invoke(target, args);
19         }
20         else
21         {
22             System.out.println("The name is null.");
23         }
24         return null;
25     }
26 }

  它实现了MethodInterceptor接口,其中包括intercept方法,这个方法就会通过反射的方式来触发目标方法,同时还可以添加一些其他处理。

  下面是测试方法:

 1 private static void test2() throws InterruptedException
 2 {
 3     CglibFactory cf = new CglibFactory();
 4     UserDaoImpl2 temp = new UserDaoImpl2();
 5     UserDaoImpl2 userDao = (UserDaoImpl2)cf.createUserDao(temp);
 6     userDao.save();
 7     temp.setName("Zhang San");
 8     userDao = (UserDaoImpl2)cf.createUserDao(temp);
 9     userDao.save();
10 }

  输出结果如下:

The name is null.
save() is called for Zhang San

  使用Spring实现AOP

  Spring框架集合了ProxyFactory和Cglib两种方式来实现AOP。

  我们来看一个示例,还是使用上面定义的UserDaoImpl以及UserDaoImpl2。

  首先需要定义一个interceptor:

 1 @Aspect
 2 public class MyInterceptor {
 3
 4     @Pointcut("execution (* sample.spring.aop.*.*(..))")
 5     public void anyMethod(){}
 6
 7     @Before("anyMethod()")
 8     public void before()
 9     {
10         System.out.println("Before");
11     }
12
13     @After("anyMethod()")
14     public void after()
15     {
16         System.out.println("After");
17     }
18
19     @Around("anyMethod()")
20     public void Around(ProceedingJoinPoint pjp) throws Throwable
21     {
22         long start = System.currentTimeMillis();
23         pjp.proceed();
24         long end = System.currentTimeMillis();
25         System.out.println("执行时间:" + (end - start));
26     }
27
28     @Before("anyMethod() && args(name)")
29     public void before(String name)
30     {
31         System.out.println("The name is " + name);
32     }
33
34     @AfterReturning(pointcut="anyMethod()", returning="result")
35     public void afterReturning(String result)
36     {
37         System.out.println("The value is " + result);
38     }
39
40     @AfterThrowing(pointcut="anyMethod()", throwing="e")
41     public void afterThrowing(Exception e)
42     {
43         e.printStackTrace();
44     }
45 }

  我们可以看到上面的代码中包含了一些Annotation,这些Annotation是用来实现AOP的关键。

  然后需要修改beans.xml,添加如下内容:

1 <aop:aspectj-autoproxy />
2 <bean id="userDaoImpl" class = "sample.spring.aop.UserDaoImpl"/>
3 <bean id="userDaoImpl2" class = "sample.spring.aop.UserDaoImpl2"/>
4 <bean id="myInterceptor" class="sample.spring.aop.MyInterceptor"/>

  其中第一行是让Spring打开AOP的功能,下面三行定义了三个bean,这里我们把interceptor也看做是一个bean对象。

  接下来是测试代码:

 1 private static void test3() throws InterruptedException
 2 {
 3     ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/aop/beans.xml");
 4     UserDao userDao = (UserDao)ctx.getBean("userDaoImpl");
 5     userDao.save();
 6     UserDaoImpl2 userDao2 = (UserDaoImpl2)ctx.getBean("userDaoImpl2");
 7     userDao2.save();
 8     userDao2.setName("Zhang San");
 9     String name = userDao2.getName();
10 //        userDao2.raiseException();
11 }

  这里我们可以看到,测试方法中既使用了UserDaoImpl1(这里是UserDao接口),也是用了UserDaoImpl2。正如我们上面所言,在Spring中,如果类实现了接口,Spring会按照ProxyFactory的方式来处理;如果没有实现接口,Spring会按照Cglib的方式来处理。

  上面测试方法的输出如下:

Before
Before
save() is called for null
执行时间:1
The value is null
After
After
执行时间:1
The value is null
Before
Before
save() is called for null
执行时间:3001
The value is null
After
After
执行时间:3002
The value is null
Before
The name is Zhang San
Before
执行时间:26
The value is null
After
After
执行时间:27
The value is null
Before
Before
执行时间:0
The value is null
After
After
执行时间:1
The value is null

  使用Spring配置文件来配置AOP

  上面的示例中,我们使用Annotation来配置AOP的信息,同样我们也可以使用xml文件的方式来配置AOP。

  还是以上面定义的interceptor为基础,我们去掉里面所有的Annotation,然后在beans.xml中添加如下内容:

 1 <bean id="myInterceptor2" class="sample.spring.aop.MyInterceptor2"/>
 2 <aop:config>
 3     <aop:aspect id="asp" ref="myInterceptor2">
 4         <aop:pointcut id="anyMethod" expression="execution (* sample.spring.aop.*.*(..))"/>
 5         <aop:before pointcut-ref="anyMethod" method="before"/>
 6         <aop:after pointcut-ref="anyMethod" method="after"/>
 7         <aop:around pointcut-ref="anyMethod" method="around"/>
 8         <aop:after-returning pointcut-ref="anyMethod" method="afterReturning" returning="result"/>
 9         <aop:after-throwing pointcut-ref="anyMethod" method="afterThrowing" throwing="e"/>
10     </aop:aspect>
11 </aop:config>

  测试方法和输出结果同上。

时间: 2024-10-03 22:37:33

Spring 之 AOP的相关文章

8 -- 深入使用Spring -- 4... Spring的AOP

8.4 Spring的AOP AOP(Aspect Orient Programming),也就是面向切面编程,最为面向对象编程的一种补充. AOP和OOP互为补充,面向对象编程将程序分解成各个层次的对象,而面向切面编程将程序运行过程分解成各个切面.可以这样理解:面向对象编程是从静态角度考虑程序结构,而面向切面编程则是从动态角度考虑程序运行过程. 8.4.1 为什么需要AOP 8.4.2 使用AspectJ实现AOP 1.下载和安装AspectJ 2.AspectJ使用入门 8.4.3 AOP的

Spring实现AOP的4种方式(转)

转自:http://blog.csdn.net/udbnny/article/details/5870076 Spring实现AOP的4种方式 先了解AOP的相关术语:1.通知(Advice):通知定义了切面是什么以及何时使用.描述了切面要完成的工作和何时需要执行这个工作.2.连接点(Joinpoint):程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时.异常被抛出时等等.3.切入点(Pointcut)通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的

Java反射—模拟Spring的Aop

1.    大概流程 上篇文章已经结合Java反射解释了SpringAop的原理,这里我们简单模拟以下Spring的Aop实现.大体流程如下: ?  创建一个properties配置文件模拟Spring配置文件. ?  创建一个增强接口与一个实现类模拟Spring的Advice. ?  创建一个生成代理的工厂类,并在InvocationHandler类的invoke方法中织入增强方法(即aop). ?  创建一个生成Bean的工厂类(类似IOC工厂,只创建bean,没有依赖注入的功能),生成Be

Spring实现AOP的4种方式

来自:http://blog.csdn.net/udbnny/article/details/5870076 先了解AOP的相关术语: 1.通知(Advice):通知定义了切面是什么以及何时使用.描述了切面要完成的工作和何时需要执行这个工作.2.连接点(Joinpoint):程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时.异常被抛出时等等.3.切入点(Pointcut)通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,S

spring的AOP个人理解和使用

1什么是AOP:AOP是面向切面编程,也就是说面向某个功能模块编程,典型的应用就是Spring的声明式事务, Spring的AOP事务解析: 在以前的事务管理是要融合在逻辑代码中的,在逻辑代码中决定事务是否提交或者回滚,这样很容易造成代码难以维护,代码冗余 但是使用spring的声明式事务后,只需要在数据库处理方法上注解事务,就可以对操作进行管理,事务的设置和逻辑代码分开,容易维护2AOP有什么作用 :面向切面编程,例如某个功能点,我们只需抽取横切关注点,然后让需要处理这些功能点的方法来使用代理

第二十八天 月出惊山鸟 —Spring的AOP

6月13日,阴转细雨."人闲桂花落,夜静春山空.月出惊山鸟,时鸣春涧中." 不管在面向过程还是在面向对象里,神奇的"纯"字,似乎永远都充满了无限的可能性.除了函数之所调用.类之所封装,在程序员文化里,对于"纯粹"的感知和定义,既起自于代码,又超越了代码.也就是说,能够真真切切地感觉到纯净的,不仅是我们的每一个Bean和每一个Class,还包括每个Coder的心. 然而,客户的需求是千变万化和千奇百怪的,Spring在为Coder在应对和处理各自不

Spring框架第五篇之Spring与AOP

一.AOP概述 AOP(Aspect Orient Programming),面向切面编程,是面向对象编程OOP的一种补充.面向对象编程是从静态角度考虑程序的结构,而面向切面编程是从动态角度考虑程序运行过程. AOP底层就是采用动态代理模式实现的,采用了两种代理:JDK的动态代理与CGLIB的动态代理. 面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP容器的功能将切面织入到主业务逻辑中.所谓交叉业务逻辑是指,通用的.与主业务逻辑无关的代码.如安全检查.事务.日志等. 若不是用AOP,则会出

Spring的AOP详解

Spring的AOP详解 一.AOP基础 1.1AOP是什么 考虑这样一个问题:需要对系统中的某些业务做日志记录,比如支付系统中的支付业务需要记录支付相关日志,对于支付系统可能相当复杂,比如可能有自己的支付系统,也可能引入第三方支付平台,面对这样的支付系统该如何解决呢? 传统解决方案 1.日志部分定义公共类LogUtils,定义logPayBegin方法用于记录支付开始日志, logPayEnd用于记录支付结果 logPayBegin(long userId,long money) logPay

spring之aop概念和配置

面向切面的一些概念: 简单说: 连接点就一些方法,在这些方法基础上需要额外的一些业务需求处理. 切入点就是方法所代表的功能点组合起来的功能需求. 通知就是那些额外的操作. 织入就是使用代理实现整个切入的过程. 引入就是已有功能代码不变的基础上,添加新属性和方法. spring使用aop首先xml添加命名空间实例; 并且要在xml 配置中添加<aop:aspectj-autoproxy/>标签,当然对象交给spring管理也要配置bean 环绕通知可以替换上面通知效果: 最终通知在例外通知前执行