JAVA AOP编程

简介

面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

主要应用场景


日志记录,性能统计,安全控制,事务处理,异常处理,PV、UV统计等等


JDKProxy

java动态代理

1.被代理类实现接口。


2.创建InvocationHandler接口实现。


3.使用Proxy.newProxyInstance()创建被代理对象。


[java]  view plain  copy



1. public interface LoginService {  
2.     String debark(String name);  
3. }

[java]  view plain  copy



1. public class LoginImp implements LoginService{  
2. public String debark(String name) {  
3. "----------登陆中----------");  
4. return name;  
5.     }  
6. }

[java]  view plain  copy



1. public class LoginProxy implements InvocationHandler{  
2. private Object target;  
3.       
4. public LoginProxy(Object obj){  
5.         target = obj;  
6.     }  
7.       
8. public Object invoke(Object proxy, Method method, Object[] args)  
9. throws Throwable {  
10.           
11. "----------"+method.getName()+"开始----------");  
12.           
13. /*调用被代理类的方法,传入参数args,得到返回*/  
14.         Object object = method.invoke(target, args);  
15.           
16. "----------"+method.getName()+"结束----------");  
17.           
18. return object;  
19.     }  
20.       
21. public Object getProxy(){  
22. return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),     
23. this);  
24.     }  
25.   
26.   
27. }


[java]  view plain  copy



1. public class TestMain {  
2. public static void main(String[] args) {  
3. new LoginImp();  
4. new LoginProxy(loginImp);  
5.         LoginService loginService = (LoginService)loginProxy.getProxy();  
6.           
7. "李连杰");  
8. "登陆人:"+name);  
9.     }  
10. }

[java]  view plain  copy




    1. /*保存生成代理类的字节码到硬盘上*/  
    2. public class ProxyGeneratorUtils {  
    3. public static void writeProxyClassToHardDisk(Class calss,String path) {    
    4. byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", calss.getInterfaces());    
    5.             
    6. null;    
    7.             
    8. try {    
    9. new FileOutputStream(path);    
    10.             out.write(classFile);    
    11.             out.flush();    
    12. catch (Exception e) {    
    13.             e.printStackTrace();    
    14. finally {    
    15. try {    
    16.                 out.close();    
    17. catch (IOException e) {    
    18.                 e.printStackTrace();    
    19.             }    
    20.         }    
    21.     }  
    22. }


    CGlib

    AOP类库:运行时生成代理扩展。

    1.引入cglib的jar包。


    [java]  view plain  copy



    1. public class LoginCglibProxy implements MethodInterceptor{  
    2.       
    3. public Object intercept(Object arg0, Method arg1, Object[] arg2,  
    4. throws Throwable {  
    5. "----------"+arg1.getName()+"开始----------");  
    6.         Object result = arg3.invokeSuper(arg0, arg2);  
    7. "----------"+arg1.getName()+"结束----------");  
    8. return result;  
    9.     }  
    10.       
    11.       
    12. public  Object getProxy(Object target){  
    13. new Enhancer();  
    14.         enhancer.setSuperclass(target.getClass());  
    15. this);  
    16.         enhancer.setClassLoader(target.getClass().getClassLoader());  
    17. return enhancer.create();  
    18.     }  
    19.   
    20.   
    21. }


    [java]  view plain  copy


    1. public static void main(String[] args) {  
    2. new LoginCglibProxy();  
    3. new LoginImp();  
    4.     LoginImp proxy = (LoginImp)loginCglibProxy.getProxy(loginService);  
    5. "李连杰");  
    6. "登陆人:"+name);  
    7. }


    AspectJ (TM)

    AOP框架:编译时增强目标类生成新类的方式,需要特殊的编译工具。

    Spring可以识别AspectJ关于方面,切入点,增强处理的注解。根据这些注解生成AOP代理。

    AspectJ AOP 声明有几个概念:

    Aspect(切面)

    Joint point和Advice

    Joint point (连接点)

    Advice执行的时机。

    Pointcut(切入点)

    Advice执行的地点,可以通过表达式来进行匹配。

    Advice(通知)

    具体的操作。

    <!-- 启动@AspectJ支持 -->


    [html]  view plain  copy



    1. <aop:aspectj-autoproxy/>

    Spring


    Spring使用JDKProxy和CGlib两种方式来生成代理对象,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。



    1.导入Spring AOP相关jar包。


    [html]  view plain  copy




      1. <dependencies>  
      2. <!-- Spring AOP 主要的jar -->  
      3. <dependency>       
      4. <groupId>org.springframework</groupId>  
      5. <artifactId>spring-core</artifactId>  
      6. <version>3.0.5.RELEASE</version>   
      7. </dependency>  
      8. <dependency>       
      9. <groupId>org.springframework</groupId>  
      10. <artifactId>spring-context</artifactId>  
      11. <version>3.0.5.RELEASE</version>  
      12. </dependency>  
      13. <dependency>       
      14. <groupId>org.springframework</groupId>  
      15. <artifactId>spring-beans</artifactId>  
      16. <version>3.0.5.RELEASE</version>  
      17. </dependency>  
      18. <!-- Spring AOP 依赖的其他jar -->  
      19. <dependency>  
      20. <groupId>org.aspectj</groupId>  
      21. <artifactId>aspectjweaver</artifactId>  
      22. <version>1.6.11</version>  
      23. </dependency>  
      24. <dependency>  
      25. <groupId>cglib</groupId>  
      26. <artifactId>cglib</artifactId>  
      27. <version>2.1</version>  
      28. </dependency>    
      29. </dependencies>


      Spring 注解方式 实现AOP


      [java]  view plain  copy




      1. public interface LoginService{  
      2. public String login(String name);  
      3. }


      [java]  view plain  copy



      1. public class LoginImpl implements LoginService{  
      2. public String login(String name) {  
      3. "-----------"+name+"登陆中-----------");  
      4. if ("李连杰".equals(name)) {  
      5. throw new Error();  
      6.         }  
      7. return name;  
      8.     }  
      9. }

        


      [java]  view plain  copy




        1. @Aspect  
        2. public class LoginHelper {  
        3. /*@Pointcut 声明一个共享的切入点*/  
        4. @Pointcut("execution(* www.wwq.test.LoginImpl.*(..))")   
        5. public void login(){}  
        6.       
        7. @Before("target(www.wwq.test.LoginService) && args(name)")  
        8. public void beforeLogin(String name){  
        9. "-----------"+name+"开始登陆-----------");  
        10.     }  
        11. @AfterThrowing("target(www.wwq.test.LoginService) && args(name)")  
        12. public void beforeThrowing(String name){  
        13. "-----------"+name+"登陆异常-----------");  
        14.     }  
        15. }


        [html]  view plain  copy



        1. <?xml version="1.0" encoding="UTF-8"?>    
        2. <beans xmlns="http://www.springframework.org/schema/beans"    
        3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
        4. xmlns:aop="http://www.springframework.org/schema/aop"    
        5. xsi:schemaLocation="    
        6.        http://www.springframework.org/schema/beans     
        7.        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
        8.        http://www.springframework.org/schema/aop     
        9. >    
        10.          
        11. <aop:aspectj-autoproxy/>  
        12. <bean id="login" class="www.wwq.test.LoginImpl"></bean>  
        13. <bean id="loginHelper" class="www.wwq.test.LoginHelper"></bean>  
        14. </beans>

        [java]  view plain  copy




        1. public class TestMain {  
        2. public static void main(String[] args) {  
        3. new ClassPathXmlApplicationContext("applicationContext.xml");  
        4. "login");  
        5. "李连杰");  
        6. "登陆人"+name);  
        7.     }  
        8. }


        Spring 配置文件方式 实现AOP


        1.删除LoginHelper中的注解。


        2.修改Spring 配置文件


        [html]  view plain  copy


        1. <?xml version="1.0" encoding="UTF-8"?>    
        2. <beans xmlns="http://www.springframework.org/schema/beans"    
        3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
        4. xmlns:aop="http://www.springframework.org/schema/aop"    
        5. xsi:schemaLocation="    
        6.        http://www.springframework.org/schema/beans     
        7.        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
        8.        http://www.springframework.org/schema/aop     
        9. >    
        10.       
        11. <bean id="login" class="www.wwq.test.LoginImpl"></bean>  
        12. <bean id="loginHelper" class="www.wwq.test.LoginHelper"></bean>  
        13.       
        14. <aop:config>  
        15. <aop:aspect id="loginAop" ref="loginHelper">  
        16. <aop:before method="beforeLogin" pointcut="target(www.wwq.test.LoginService) and args(name)"/>  
        17. <aop:after method="beforeThrowing" pointcut="target(www.wwq.test.LoginService) and args(name)"/>  
        18. </aop:aspect>  
        19. </aop:config>  
        20. </beans>

        Spring AOP 注解


        [plain]  view plain  copy



        1. @Aspect 声明一个切面。  
        2. @Before 匹配方法执行之前。  
        3. @AfterReturning 匹配方法正常返回之后。  
        4. @AfterThrowing 匹配方法抛出异常之后。  
        5. @After 匹配方法执行之后(无论是否抛出异常)。  
        6. @Around


        Spring AOP 切入点表达式


        [plain]  view plain  copy



        1. 1. execution(public * *(..))   
        2.     所有public方法。  
        3. 2. execution(* set*(..))   
        4.     所有以set开头的方法。  
        5. 3. execution(* www.wwq.test.LoginService.*(..))  
        6.     LoginService接口定义的方法  
        7. 4. execution(* www.wwq.test.*.*(..))  
        8.     test包下的所有方法  
        9. 5.  execution(* www.wwq.test..*.*(..))  
        10.     test包下/包里的所有方法  
        11. 6. within(www.wwq.test.*)  
        12.     test包下的所有方法  
        13. 7. within(www.wwq.test..*)  
        14.     test包下/包里的所有方法  
        15. 8. this(www.wwq.test.LoginService)  
        16.     代理对象实现LoginService接口  
        17. 9. target(www.wwq.test.LoginService)  
        18.     目标对象实现LoginService接口  
        19. 10. args(java.io.Serializable)  
        20.        任何在运行时传递的参数有可序列化的。  
        21. 11. @target(org.springframework.transaction.annotation.Transactional)  
        22.        任何有@Transactional注解的连接点(对象)  
        23. 12. @within(org.springframework.transaction.annotation.Transactional)  
        24.        任何有@Transactional注解的连接点(对象)  
        25. 13. @annotation(org.springframework.transaction.annotation.Transactional)  
        26.        任何有@Transactional注解的连接点(方法)  
        27. 14. @args(www.wwq.test.Parameter)  
        28.        任何在运行时传递的参数类型有@Parameter注解的连接点  
        29. 15. bean(tradeService)  
        30.        任何Spring bean名为tradeService”的连接点  
        31. 16. bean(*Service)  
        32.      Spring bean名称匹配通配符表达式"*Service"

        Spring AOP XML标签


        [plain]  view plain  copy




        1. <aop:config> AOP声明。  
        2. <aop:aspect id="" ref=""> 声明一个切面  
        3. <aop:pointcut id="" expression=""> 声明一个切入点(共享)  
        4. <aop:before pointcut-ref="" method=""/> 匹配方法执行之前  
        5. <aop:after-returning pointcut-ref="" method=""/> 匹配方法正常返回之后  
        6. <aop:after-throwing pointcut-ref="" method=""/> 匹配方法抛出异常之后  
        7. <aop:after pointcut-ref="" method=""/> 匹配方法执行之后(无论是否抛出异常)  
        8. <aop:around pointcut-ref="" method=""/>  
        9. expression 匹配表达式  
        10. pointcut-ref 匹配表达式  
        11. method 执行方法  
        12. throwing 指定异常名称  
        13. arg-names 指定参数名称,以逗号分隔的参数名称列表。