您当前的位置: 首页 > 

Dongguo丶

暂无认证

  • 2浏览

    0关注

    472博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

切面编程的实现

Dongguo丶 发布时间:2017-11-28 21:20:13 ,浏览量:2

1、面向切面的定义自行百度

2、面向切面编程的应用场景自己想象,大概就是日志之类的地方

3、上面两句话基本是废话

实现方式一,在XML中声明切面

1、编写一个原始类

[java] view plain copy
print ?
  1. package com.hsb.beans;  
  2.   
  3. import org.springframework.stereotype.Repository;  
  4.   
  5. @Repository  
  6. public class Perform {  
  7.     public void show(){  
  8.         System.out.println(”message from Perform.show()”);  
  9.     }  
  10. }  
package com.hsb.beans;

import org.springframework.stereotype.Repository;

@Repository
public class Perform {
    public void show(){
        System.out.println("message from Perform.show()");
    }
}
本例中show()方法就是切点。在一个大型项目中,许多个切点构成了切面,这些切面实际上是为了某些共同的东西而成为一个面的。 2、编写一个切面类

[java] view plain copy
print ?
  1. package com.hsb.aop;  
  2.   
  3. import org.aspectj.lang.ProceedingJoinPoint;  
  4.   
  5. public class Audience {  
  6.     public void beforeShow(){  
  7.         System.out.println(”message from beforeShow”);  
  8.     }  
  9.     public void afterShow(){  
  10.         System.out.println(”message from afterShow”);  
  11.     }  
  12.     public void around(ProceedingJoinPoint joinpoint){  
  13.         System.out.println(”message from Start around”);  
  14.         long start = System.currentTimeMillis();  
  15.         try {  
  16.             joinpoint.proceed();  
  17.         } catch (Throwable e) {  
  18.             e.printStackTrace();  
  19.         }  
  20.         long end = System.currentTimeMillis();  
  21.         System.out.println(”message from End around total : ”+(end-start)+“ ms”);  
  22.     }  
  23. }  
package com.hsb.aop;

import org.aspectj.lang.ProceedingJoinPoint;

public class Audience {
    public void beforeShow(){
        System.out.println("message from beforeShow");
    }
    public void afterShow(){
        System.out.println("message from afterShow");
    }
    public void around(ProceedingJoinPoint joinpoint){
        System.out.println("message from Start around");
        long start = System.currentTimeMillis();
        try {
            joinpoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("message from End around total : "+(end-start)+" ms");
    }
}

注意代码中的joinpoint.proceed(),这句话就是实际调用切点方法,也就是本例中的show()。如果切面类中定义了around通知,通知一定要加上这句话,否则要切点方法不会被调用!此处应该是一个坑,一定要记住,免得后面找bug到处都找不到。

3、配置XML

[html] view plain copy
print ?
  1.   
  2.   
  3.       
  4.       
  5.       
  6.           
  7.               
  8.               
  9.               
  10.               
  11.           
  12.       
  13.   


    
    
    
        
            
            
            
            
        
    
注意,上面的将切面类生命为一个bean,而声明中引用了这个bean.简单解释一下声明中各句的意思。配置声明的时候,一定注意使用英文字符进行配置,不然会报很多稀奇古怪的错误,大致就是说切面无法使用或者其他什么的。

[html] view plain copy
print ?
  1.   
声明了一个切点(pointcut),后面声明的通知会引用。

通知一共有五种分别是、、、、。根据其字面意思大概就能懂其应用场景,而around上面已经说过了,标识出切点位置,在切点前后做某些工作。

4、测试

[java] view plain copy
print ?
  1. package com.hsb.dao;  
  2.   
  3. import org.junit.Test;  
  4. import org.junit.runner.RunWith;  
  5. import org.springframework.beans.factory.annotation.Autowired;  
  6. import org.springframework.test.context.ContextConfiguration;  
  7. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  8.   
  9. import com.hsb.beans.Perform;  
  10.   
  11. @RunWith(SpringJUnit4ClassRunner.class)  
  12. @ContextConfiguration({“classpath*:**/applicationContext.xml”,“classpath*:**/springmvc-servlet.xml”})  
  13. public class PerformTests {  
  14.     @Autowired  
  15.     private Perform perform;  
  16.   
  17.     @Test  
  18.     public void testShow() {  
  19.         perform.show();  
  20.     }  
  21.   
  22. }  
package com.hsb.dao;

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

import com.hsb.beans.Perform;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:**/applicationContext.xml","classpath*:**/springmvc-servlet.xml"})
public class PerformTests {
    @Autowired
    private Perform perform;

    @Test
    public void testShow() {
        perform.show();
    }

}
上面的代码使用自动注入生成一个Perform实例,在测试方法中调用切点方法show().

5、Console打印结果

[html] view plain copy
print ?
  1. 九月 05, 2016 9:54:03 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions  
  2. 信息: Loading XML bean definitions from file [D:\PractiseForWork\WorkSpace\HelloMaven\target\classes\applicationContext.xml]  
  3. 九月 05, 2016 9:54:04 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh  
  4. 信息: Refreshing org.springframework.context.support.GenericApplicationContext@6e3c1e69: startup date [Mon Sep 05 21:54:04 CST 2016]; root of context hierarchy  
  5. message from beforeShow  
  6. message from Start around  
  7. message from Perform.show()  
  8. message from End around total : 38 ms  
  9. message from afterShow  
九月 05, 2016 9:54:03 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from file [D:\PractiseForWork\WorkSpace\HelloMaven\target\classes\applicationContext.xml]
九月 05, 2016 9:54:04 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.GenericApplicationContext@6e3c1e69: startup date [Mon Sep 05 21:54:04 CST 2016]; root of context hierarchy
message from beforeShow
message from Start around
message from Perform.show()
message from End around total : 38 ms
message from afterShow
从Console的打印结果中,我们可以猜测出五种通知的具体用法

6、Maven工程一定要添加依赖

[html] view plain copy
print ?
  1.                 
  2.     org.aspectj  
  3.     aspectjrt  
  4.     1.6.12  
  5.   
  6.   
  7.     org.aspectj  
  8.     aspectjweaver  
  9.     1.6.12  
  10.   
                
            org.aspectj
            aspectjrt
            1.6.12
        
        
            org.aspectj
            aspectjweaver
            1.6.12
        
如果不添加上述依赖,极有可能会测试报错。

实现方式二,注解切面

1、编写一个原始类

[java] view plain copy
print ?
  1. package com.hsb.beans;  
  2.   
  3. import org.springframework.stereotype.Repository;  
  4.   
  5. @Repository  
  6. public class Perform {  
  7.     public void show(){  
  8.         System.out.println(”message from Perform.show()”);  
  9.     }  
  10. }  
package com.hsb.beans;

import org.springframework.stereotype.Repository;

@Repository
public class Perform {
    public void show(){
        System.out.println("message from Perform.show()");
    }
}
2、编写一个切面类

[java] view plain copy
print ?
  1. package com.hsb.aop;  
  2.   
  3. import org.aspectj.lang.ProceedingJoinPoint;  
  4. import org.aspectj.lang.annotation.After;  
  5. import org.aspectj.lang.annotation.Around;  
  6. import org.aspectj.lang.annotation.Aspect;  
  7. import org.aspectj.lang.annotation.Before;  
  8. import org.aspectj.lang.annotation.Pointcut;  
  9. import org.springframework.stereotype.Component;  
  10.   
  11. @Aspect  
  12. @Component  
  13. public class Audience {  
  14.     @Pointcut(“execution(* com.hsb.beans.Perform.show(..))”)  
  15.     public void performance() {  
  16.     }  
  17.   
  18.     @Before(“performance()”)  
  19.     public void beforeShow() {  
  20.         System.out.println(”message from beforeShow”);  
  21.     }  
  22.   
  23.     @After(“performance()”)  
  24.     public void afterShow() {  
  25.         System.out.println(”message from afterShow”);  
  26.     }  
  27.   
  28.     @Around(“performance()”)  
  29.     public void around(ProceedingJoinPoint joinpoint) {  
  30.         System.out.println(”message from Start around”);  
  31.         long start = System.currentTimeMillis();  
  32.         try {  
  33.             joinpoint.proceed();  
  34.         } catch (Throwable e) {  
  35.             e.printStackTrace();  
  36.         }  
  37.         long end = System.currentTimeMillis();  
  38.         System.out.println(”message from End around total : ” + (end - start)  
  39.                 + ” ms”);  
  40.     }  
  41. }  
package com.hsb.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class Audience {
    @Pointcut("execution(* com.hsb.beans.Perform.show(..))")
    public void performance() {
    }

    @Before("performance()")
    public void beforeShow() {
        System.out.println("message from beforeShow");
    }

    @After("performance()")
    public void afterShow() {
        System.out.println("message from afterShow");
    }

    @Around("performance()")
    public void around(ProceedingJoinPoint joinpoint) {
        System.out.println("message from Start around");
        long start = System.currentTimeMillis();
        try {
            joinpoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("message from End around total : " + (end - start)
                + " ms");
    }
}
@Aspect将此类声明为切面类,@Component将此类声明为bean放到spring容器中,@Pointcut将下面的performance声明为一个切点,并将Perform中的show()方法进行了关联。execution(* com.hsb.beans.Perform.show(..))的意思是,执行此方法时,忽略返回值,参数类型和个数忽略。还可以更加简写,用于匹配合适的方法,譬如对Perform类的全部方法进行匹配就是com.hsb.beans.Perform.*。

3、配置xml

[html] view plain copy
print ?
  1.   
  2.   
  3.       
  4.       
  5.   


    
    
可以看见此处就没有使用声明,而是使用。这句话的意思是自动在spring上下文中创建一个AnnotationAwareAspectJAutoProxyCreator类,它会自动代理一些bean,这些bean的方法需要与使用@Aspect注解的bean中所定义的切点相匹配,而这些切点又是使用@Pointcut注解定义出来的。proxy-target-class=”true”的意思是使用基于类的代理使用 cglib库,如果为false则使用jdk自带的基于接口的代理

4、测试

[java] view plain copy
print ?
  1. package com.hsb.dao;  
  2.   
  3. import org.junit.Test;  
  4. import org.junit.runner.RunWith;  
  5. import org.springframework.beans.factory.annotation.Autowired;  
  6. import org.springframework.test.context.ContextConfiguration;  
  7. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  8.   
  9. import com.hsb.beans.Perform;  
  10.   
  11. @RunWith(SpringJUnit4ClassRunner.class)  
  12. @ContextConfiguration({“classpath*:**/applicationContext.xml”,“classpath*:**/springmvc-servlet.xml”})  
  13. public class PerformTests {  
  14.     @Autowired  
  15.     private Perform perform;  
  16.   
  17.     @Test  
  18.     public void testShow() {  
  19.         perform.show();  
  20.     }  
  21.   
  22. }  
package com.hsb.dao;

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

import com.hsb.beans.Perform;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:**/applicationContext.xml","classpath*:**/springmvc-servlet.xml"})
public class PerformTests {
    @Autowired
    private Perform perform;

    @Test
    public void testShow() {
        perform.show();
    }

}
5、Console打印结果

[html] view plain copy
print ?
  1. 九月 05, 2016 10:24:46 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions  
  2. 信息: Loading XML bean definitions from file [D:\PractiseForWork\WorkSpace\HelloMaven\target\classes\applicationContext.xml]  
  3. 九月 05, 2016 10:24:47 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh  
  4. 信息: Refreshing org.springframework.context.support.GenericApplicationContext@6e3c1e69: startup date [Mon Sep 05 22:24:47 CST 2016]; root of context hierarchy  
  5. message from Start around  
  6. message from beforeShow  
  7. message from Perform.show()  
  8. message from End around total : 39 ms  
  9. message from afterShow  
九月 05, 2016 10:24:46 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from file [D:\PractiseForWork\WorkSpace\HelloMaven\target\classes\applicationContext.xml]
九月 05, 2016 10:24:47 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.GenericApplicationContext@6e3c1e69: startup date [Mon Sep 05 22:24:47 CST 2016]; root of context hierarchy
message from Start around
message from beforeShow
message from Perform.show()
message from End around total : 39 ms
message from afterShow

如上所示,完全是一样的效果。可以看出使用注解减少了很多工作,不容易出错,各个组件间的耦合度降低了。试想,如果一个大型项目中有很多切面,切点,如果全部去xml中配置,将会是一项极为艰苦的工作,但是如果使用注解就可以做很少的工作完成这一切。

后记一、使用注解时一定要使用@component或者@Repository、@Controller、@Service中一个去声明,将切面类放入到spring容器中,不然就去xml中显式写一个bean,不然的话就会报错,无法实现切面功能。

关注
打赏
1638062488
查看更多评论
立即登录/注册

微信扫码登录

0.0408s