zoukankan      html  css  js  c++  java
  • Spring 之 AOP

    本文参考文章:http://www.cnblogs.com/wing011203/archive/2013/05/15/3078849.html

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

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

  • 相关阅读:
    JeePlus:代码生成器
    JeePlus:API工具
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
  • 原文地址:https://www.cnblogs.com/Jtianlin/p/4456218.html
Copyright © 2011-2022 走看看