码迷,mamicode.com
首页 > 编程语言 > 详细

Spring 之 AOP

时间:2016-07-21 23:41:39      阅读:292      评论:0      收藏:0      [点我收藏+]

标签:

面向方面的编程,即 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>

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

Spring 之 AOP

标签:

原文地址:http://www.cnblogs.com/doudouxiaoye/p/5693383.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!