`
wataxi
  • 浏览: 208966 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

深入浅出 spring AOP

阅读更多

深入浅出 spring AOP (一)    源出处


先不讨论AOP的各种名词,也不作各种AOP的比较,我将在例子中介绍各种名词。
1。先写一个javabean,就是target object。

package org.tatan.test;

public class MessageBean {

public void write() {

         System.out.print("AOP example");
     }

}
2。写一个AOP的advice类MethodInterceptor是AOP联盟的标准接口,它是最简单最实用的连接点(joinpoint),实现了around advice ,你可以在他返回前调用target的方法。

package org.tatan.test;

import org.aopalliance.intercept.MethodInterceptor;

import org.aopalliance.intercept.MethodInvocation;

public class MessageCode implements MethodInterceptor {

public Object invoke(MethodInvocation invocation) throws Throwable {

    System.out.print("this is a ");

        Object returnValue = invocation.proceed();

        return returnValue ;

    }

}
3。把MessageCode advice weave 到proxy factory,proxy factory是整个架构的核心
先创建instance of MessageBean,然后创建代理的instance ,MessageCode advice 传递给的
addAdvice()方法,设置Target Object,调用getProxy()产生代理对象。

import org.springframework.aop.framework.ProxyFactory;

public class AOPExample {

  public static void main(String[] args) {

          MessageBean target = new MessageBean();

          ProxyFactory pf = new ProxyFactory();

         pf.addAdvice(new essageCode());

     pf.setTarget(target);
         MessageBean proxy = (MessageBean) pf.getProxy();

         //输出原始信息

         target.write();

        //输出代理对象调用的信息
         proxy.write();   

 }
}
4。classpath中加入cglib-nodep-2.1_2.jar ,spring.jar,aopalliance.jar,commons-logging.jar
结果
AOP example
this is a AOP example

深入浅出 spring AOP (二)
有人问我,为什末使用CGLIB proxy而不使用JDK Dynamic Proxies,这和spring aop使用的原则相关。

<!--[if !supportLists]-->1.      <!--[endif]-->使用AOP的时候,尽可能的使用接口,而不是使用具体的类,这样就可以使用JDK Dynamic Proxies,如果目标类没有实现接口,spring使用CGLIB生成目标类的子类。下面给个例子接口类
package org.tatan.test;

public interface Worker {

        void doSomeWork(int numOfTimes);

    }

 
目标类
package org.tatan.test;

 public class WorkerBean implements Worker {
    public void doSomeWork(int numOfTimes) {

        for (int i = 0; i < numOfTimes; i++) {

System.out.print("");
        }

    }

}
Advice执行流程
package org.tatan.test;

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;

 import org.aopalliance.intercept.MethodInvocation;

public class AroundAdvice implements MethodInterceptor {

public Object invoke(MethodInvocation invocation) throws Throwable {

        Object returnValue = invocation.proceed();

        Method m = invocation.getMethod();

        Object target = invocation.getThis();

        Object[] args = invocation.getArguments();

        System.out.println("Executed method: " + m.getName());

        System.out.println("On object of type: " + target.getClass().getName());

        System.out.println("With arguments:");

        for (int i=0;i<args.length;i++) {

            System.out.println("---->" + args[i]);

        }

        System.out.println();

             return returnValue;

    }

}
运行
package org.tatan.test;

 import org.springframework.aop.framework.ProxyFactory;

public class AOPExample2 {

    public static void main(String[] args) {

        Worker bean = getWorkerBean();

        bean.doSomeWork(100000000);

    }

    private static Worker getWorkerBean() {
        WorkerBean target = new WorkerBean();
        ProxyFactory pf = new ProxyFactory();
        pf.setTarget(target);
        pf.addAdvice(new AroundAdvice());
        pf.setInterfaces(new Class[]{Worker.class});
        return (Worker) pf.getProxy();
    }
}

如果调用了setInterfaces();就不要cglib了,使用JDK Dynamic Proxies,只是使用JDK Dynamic Proxies程序执行的效率比较低。
使用CGLIB的Frozen效率比标准的CGLIB效率高。

package org.tatan.test;

import org.springframework.aop.framework.ProxyFactory;

public class AOPExample2 {

    public static void main(String[] args) {

        Worker bean = getWorkerBean();

        bean.doSomeWork(100000000);

    }

    private static Worker getWorkerBean() {

        WorkerBean target = new WorkerBean();

        ProxyFactory pf = new ProxyFactory();

        pf.setTarget(target);

        pf.addAdvice(new AroundAdvice());

     //  pf.setInterfaces(new Class[]{Worker.class});

        pf.setFrozen(true);

        return (Worker) pf.getProxy();

    }

}
<!--[if !supportEmptyParas]--> <!--[endif]-->
原则上使用CGLIB,因为既可以使用类,还可以使用接口,JDK proxy 只能代理口。
2.目标类的方法不能是final的,因为spring要生成目标类的子类,任何要advised的方法都要overide,所以不允许final method。

<!--[if !supportEmptyParas]--> <!--[endif]-->
深入浅出 spring AOP (三)
spring AOP使用,使用CGLIB应该使用接口不是类,这点务必注意。
使用BeanNameAutoProxyCreator声明事务,

<!-- define transaction interceptor -->

<bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">

<property name="transactionManager"><ref bean="transactionManager"/></property>

<property name="transactionAttributeSource"><ref bean="txAttributes"/></property>

</bean>
<!-- Define transactional methods (NameMatchTransactionAttributeSource

applies specific attributes to methods that match to a pattern) -->

<bean id="txAttributes" class="org.springframework.transaction.interceptor.

NameMatchTransactionAttributeSource">
<property name="properties">

<value>add*=PROPAGATION_REQUIRED  update*=PROPAGATION_REQUIRED delete*=PROPAGATION_REQUIRED
</value>
</property>
</bean>
<!-- 使用Autoproxy定义事务的beans,应用于Controllers -->

<!--[if !supportEmptyParas]--> <!--[endif]-->
<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

<property name="interceptorNames"><value>txInterceptor</value></property>

<property name="beanNames"><value>*Controller</value></property>

</bean>
<!-- 事务管理的beans -->

<bean id="userManager" class="com.tatan.domain.user.UserManager" singleton="true" dependency-check="objects">

<constructor-arg index="0"><ref bean="userController"/></constructor-arg>

</bean>
spring文档说明“when BeanNameAutoProxyCreator postprocesses the target object and create the proxy, it causes the proxy to be inserted into the Application context under the name of the original bean”,
UserController 应该是个接口,而不是类,默认情况下,spring使用dynamic proxies,它只使用接口。如果使用CGLIB,最好proxyTargetClass设为true。
使用TransactionProxyFactoryBean也是如此

<!--[if !supportEmptyParas]--> <!--[endif]-->
<bean id="MimeTarget" class="com。tatan.task.MimeTarget">

   <property name="sessionFactory"><ref bean="sessionFactory"/></property>      

 <property name="MimeDao"><ref bean="MimeDao"/></property>

</bean>
<!--[if !supportEmptyParas]--> <!--[endif]-->
<bean id="MimeTargetProxyFactoryBean" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

        <property name="transactionManager">

<ref bean="transactionManager"/></property>

        <property name="target"><ref local="MimeTarget"/></property>

        <property name="transactionAttributes">

            <props>

                <prop key="insert*">PROPAGATION_REQUIRED</prop>

            </props>

        </property>

    </bean>
<!--[if !supportEmptyParas]--> <!--[endif]-->
<bean id="MimeTrigger" class="org.springframework.scheduling.timer.ScheduledTimerTask">

<property name="timerTask"><ref bean="MimeTargetProxyFactoryBean"/></property>

<property name="delay"><value>1000</value></property>

<property name="period"><value>500000</value></property>

</bean>
<!--[if !supportEmptyParas]--> <!--[endif]-->
这样会抛出异常,exception org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy0] to required type [java.util.TimerTask] for property 'timerTask'; nested exception is java.lang.IllegalArgumentException: argument type mismatch
TimerTask是个类,只能用CGLIB产生代理,TransactionProxyFactoryBean 默认使用接口来产生target object,将proxyTargetClass = true即可使用CGLIB proxy代理。

<!--[if !supportEmptyParas]--> <!--[endif]-->
深入浅出 spring AOP (四)
spring的Advice分为5种,Before,After returning,Around,Throws,Introduction。使用这些Advice可以完成AOP相关部分90%的编码,剩余的10%只好依靠AspectJ了。在大多数情况下,around advice可以完成Before,After returning,Throws的所有功能。Before advice是比较有用的advice,它可以修改传递给method的参数,可以通过异常中断method的执行,通常用于检测用户的权限。Servlet过滤器是Before advice的一种方式,提供了在servlet调用前执行其他处理的能力。

下面给个例子接口
package org.tatan.test;

 public interface Worker {

void doSomeWork(int numOfTimes);

 }
类文件
package org.tatan.test;

public class WorkerBean implements Worker {

    public void doSomeWork(int numOfTimes) {

        for (int i = 0; i < numOfTimes; i++) {

            System.out.print(i);

        }

    }

}
advice
package org.tatan.test;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

import org.springframework.aop.framework.ProxyFactory;

import org.springframework.beans.factory.support.AbstractBeanFactory;

import org.springframework.beans.factory.xml.XmlBeanFactory;

import org.springframework.core.io.ClassPathResource;

import org.springframework.core.io.Resource;

public class SimpleBeforeAdvice implements MethodBeforeAdvice {

      public static void main(String[] args) {

     Resource res = new ClassPathResource("org/tatan/test/bean2.xml");

        AbstractBeanFactory ft = new XmlBeanFactory(res);

        //Instantiate an object

        Worker testObject = (Worker) ft.getBean("businesslogicbean");

        testObject.doSomeWork(100);

}
 public void before(Method method, Object[] args, Object target)

throws Throwable {   
    System.out.println("Before method: " + method.getName());

    }

}
配置文件
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
 <bean id="businesslogicbean"

  class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="proxyTargetClass">

   <value>true</value>
  </property>
  <property name="singleton">
   <value>false</value>
  </property>
  <property name="exposeProxy">
   <value>true</value>
  </property>
  <property name="proxyInterfaces">
   <value>org.tatan.test.Worker</value>
  </property>
  <property name="target">
   <ref local="beanTarget" />
  </property>
  <property name="interceptorNames">

   <list>
    <value>BeforeAdvice</value>
<value>loggingInterceptor</value>
</list>
</property>
 </bean>
 <bean id="BeforeAdvice" class="org.tatan.test.SimpleBeforeAdvice" />

 <bean id="loggingInterceptor"
  class="org.springframework.aop.interceptor.TraceInterceptor" />

 <bean id="beanTarget" class="org.tatan.test.WorkerBean" />

</beans>
Spring使用TraceInterceptor,你可以把她添加到你的代理bean中当作一个拦截器。TransactionProxyFactoryBean有"preInterceptors"和 "postInterceptors"属性,ProxyFactoryBean只有"interceptorNames"属性,这和springlive第九章有点出入,log4j配置文件,详见我的blog(http://blogger.org.cn/blog/more.asp?name=hongrui&id=7968#11881
log4j.properties

log4j.rootLogger=INFO,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n

log4j.logger.org.springframework.aop.interceptor.TraceInterceptor=DEBUG
commons-logging.properties
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4Jlogger
写这篇blog的时候,得到竹十一的大力协助,在此表示感谢。
深入浅出 spring AOP (五)
在spring的配置文件中,数据库密码是明文的,如何保护你的数据库密码,使用spring的MethodInvokingFactoryBean可以轻易做到。
配置文件
 <property name="password">

        <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">

        <property name="targetClass" >

           <value>com.tatan.util.XxxUtil</value>

         </property>
        <property name="targetMethod">

<value>decryptPassword</value>
            </property>

        <property name="arguments">

         <value>saflj</value>

        </property>
      </bean>
    </property>
java类
package com.tatan.util;
public class XxxUtil {
public static String decryptPassword(String password)
    {
        return new String("Iamstupid");

    }
}
注意 decryptPassword必须是static,参数可以是List,或Map
深入浅出 spring AOP (六)

前面的几个例子都是拦截所有类的所有方法,但是我们主要是拦截某些类的某些方法,使用Pointcut可以做到。pointcut是一系Joinpoint的集合,它定义了需要注入advice的位置。AOP框架必须允许开发者指定切入点,advisor是pointcut和advice的装配器,是将advice织入预定义位置的代码中。

Pointcut的定义
public interface Pointcut {
        ClassFilter getClassFilter (); 

MethodMatcher getMethodMatcher();
}
Pointcut interface只有两个方法,返回ClassFilter and MethodMatcher的实例。ClassFilter接口被用来将切入点限制到一个给定的目标类的集合。 如果matches()永远返回true,所有的目标类都将被匹配。

 public interface ClassFilter {
boolean matches(Class clazz);
}
MethodMatcher接口如下:
public interface MethodMatcher {
    boolean matches(Method m, Class targetClass);
    boolean isRuntime();
boolean matches(Method m, Class targetClass, Object[] args);
 }
matches(Method, Class) 方法被用来测试这个切入点是否匹配目标类的给定方法。这个测试可以在AOP代理创建的时候执行,避免在所有方法调用时都需要进行 测试。如果2个参数的匹配方法对某个方法返回true,并且MethodMatcher的 isRuntime()也返回true,那么3个参数的匹配方法将在每次方法调用的时候被调用。这使切入点能够在目标通知被执行之前立即查看传递给方法调用的参数。

大部分MethodMatcher都是静态的,意味着isRuntime()方法 返回false。这种情况下3个参数的匹配方法永远不会被调用。
如果可能,尽量使用静态切入点。spring提供Pointcut interface的7种实现,详见它的文档。

在使用Pointcut之前,必须先创建Advisor或指定PointcutAdvisor。一个advisor就是一个aspect的完整的模块化表示,一个advisor应该包括通知和切入点。Spring中很多内建的切入点都有对应的PointcutAdvisor,DefaultPointcutAdvisor 是最通用的advisor类,它可以和ethodInterceptor、 BeforeAdvice或者ThrowsAdvice一起使用。在应用较小时,只有很少类需要被切入时,ProxyFactoryBean 可以使用。当有许多类需要被切入时,为每个代理创建ProxyFactoryBean就显得很繁琐。可以通过容器来创建代理。Spring提供了两个类实现自动代理:BeanNameAutoProxyCreator和DefaultAdvisorAutoProxyCreator。BeanNameAutoProxyCreator为匹配名字的Bean产生代理,它可以使用在将一个或者多个aspect应用在命名相似的Bean中。

自动代理框架假设代理将要暴露出什么接口。如果目标Bean没有实现任何接口,这时就会动态产生一个子类。
最有效自动代理是DefaultAdvisorAutoProxyCreator,你只需要在BeanFactory中包含它的配置。他使用实现了BeanPostProcessor接口。在Bean定义被加载倒Spring容器中后,DefaultAdvisorAutoProxyCreator将搜索配置文件中的Advisor,最后它将Advisor应用到匹配Advisor切入点的Bean中。
注意:这个代理只对Advisor起作用,它需要通过Advisor来得到需要通知的Bean。
还有元数据自动代理(MetaData AutoProxy),元数据自动代理配置依赖于源代码属性而不是外部XML配置文件。这可以非常方便的使源代码和AOP元数据组织在同一个地方。元数据自动代理最常用的地方是用来声明事务。
下面举个非常有用的例子,拦截DataSource的getConnection,用于查看数据连接的处理advisor类
package com.tatan;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;
public class MyAdvice  implements MethodInterceptor {
   public Object invoke(MethodInvocation invocation) throws Throwable {

        Object returnValue = invocation.proceed();

        Method m = invocation.getMethod();

        Object target = invocation.getThis();

        Object[] args = invocation.getArguments();

        System.out.println("Executed method: " + m.getName());

        System.out.println("On object of type: " + target.getClass().getName());

        if(args!=null)
        {
for (int i=0;i<args.length;i++) {
            System.out.println("---->" + args[i]);

        }
        }
        return returnValue;
    }
}
 <bean id="myAdvice" class="com.tatan.MyAdvice"/>

<bean id="myAdvisor"
          class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">

        <property name="advice">

            <ref local="myAdvice"/>

        </property>
        <property name="mappedName">

            <value>getConnection</value>

        </property>
    </bean>
<bean id="dataSourceProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="interceptorNames">

            <list>

                <value>myAdvisor</value>

            </list>

        </property>
        <property name="beanNames">

            <list>

                <value>dataSource</value>

            </list>

        </property>
    </bean>
<!--[if !supportEmptyParas]--> <!--[endif]-->


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Jyeafee/articles/575972.aspx

分享到:
评论

相关推荐

    深入浅出学spring

    《深入浅出学Spring》这一教学视频为Spring框架的学习提供了详尽且易懂的指导,尤其适合初学者。Spring框架是Java平台上的一个开源框架,它提供了一种全面的基础架构支持,让Java开发者能够开发出更为简洁、高效的...

    aop深入浅出

    对Spring AOP的简化描述,易懂!!!

    Spring框架系列(4) - 深入浅出Spring核心之面向切面编程(AOP).doc

    【Spring 框架系列(4) - 深入浅出 Spring 核心之面向切面编程(AOP)】 面向切面编程(AOP),全称为 Aspect Oriented Programming,是Spring框架的重要特性之一,用于实现代码的解耦,提高可维护性和可复用性。AOP的...

    初识 Spring Security - v1.1.pdf

    **Spring Security**是一种广泛应用于Java企业级项目中的安全框架,它基于Spring AOP(面向切面编程)和Servlet过滤器来提供全面的安全解决方案。该框架能够在Web请求级别以及方法调用级别处理身份验证...

    Spring Security 3.pdf

    Spring Security 3集成了Spring的面向切面编程(AOP),允许在方法级别进行安全控制。`@Secured`和`@PreAuthorize`注解可以用来指定方法的访问权限。 七、国际化的支持 Spring Security 3支持多语言,可以定制错误...

    spring boot 深入浅出源码

    《Spring Boot 深入浅出源码解析》 Spring Boot是Java开发中的一个关键框架,它极大地简化了创建和配置基于Spring的应用程序。在深入理解Spring Boot的源码时,我们首先要明白其核心设计理念——“约定优于配置”。...

    深入浅出学Spring_Web_MVC

    ### 深入浅出学Spring Web MVC #### 一、Spring Web MVC 概述 **Spring Web MVC** 是一种轻量级的、基于MVC(Model-View-Controller)设计模式的Web应用框架,是Spring框架的重要组成部分之一。它为开发者提供了...

    Spring深入浅出教程

    本教程旨在帮助开发者深入理解Spring的核心概念和技术,从而更好地应用在实际项目中。 1. **依赖注入(Dependency Injection,DI)**:Spring的核心特性之一,允许开发者将对象之间的依赖关系解耦,使得组件之间...

    Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现.doc

    Spring AOP 实现原理详解之 AOP 切面的实现 Spring AOP 是基于 IOC 的 Bean 加载来实现...本文主要介绍了 Spring AOP 实现原理之 AOP 切面的实现过程,为读者提供了一个深入浅出地理解 Spring AOP 的实现机理的机会。

    spring-aop.zip

    雷丰阳老师的Spring AOP教程深入浅出地讲解了这一概念,通过源代码分析,使开发者能够更好地理解和应用。 首先,我们要理解AOP的基本概念。AOP是一种编程范式,它将关注点(如日志、安全检查等)从主业务逻辑中分离...

    Spring深入浅出教程.doc

    本教程将深入浅出地介绍Spring的主要特性、基本实例以及如何搭建和测试环境。 1. 依赖注入与控制反转 依赖注入是Spring的核心机制,它允许在运行时由外部容器(如Spring的ApplicationContext)动态地向组件提供其...

    深入浅出学习spring(1)

    本文将深入浅出地介绍Spring的核心概念,包括依赖注入、AOP(面向切面编程)、IoC(控制反转)以及Spring在实际项目中的应用。我们将通过实例演练来加深对Spring的理解。 首先,让我们从依赖注入(Dependency ...

    SPRING技术内幕:深入解析SPRING架构与设计原理

    第二部分深入阐述了各种基于IoC容器和AOP的Java EE组件在Spring中的实现原理;第三部分讲述了ACEGI安全框架、DM模块以及Flex模块等基于Spring的典型应用的设计与实现。论你是Java程序员、Spring开发者,还是平台开发...

    Spring Security.pdf

    Spring Security利用了Servlet过滤器、Spring的依赖注入(IOC)和面向切面编程(AOP)技术,它能够处理身份认证(Authentication)和授权(Authorization)两大安全核心问题。 身份认证是确认用户身份的过程,即...

    深入浅出Struts2.pdf

    总之,“深入浅出Struts2”这份资料全面讲解了Struts2的各个关键组成部分,包括其工作原理、配置方式、拦截器机制、OGNL表达式、插件使用以及与Spring的整合,是学习和掌握Struts2框架的宝贵资源。通过深入学习和...

    Spring 3.x 企业应用开发实战.pdf

    这本书深入浅出地介绍了如何利用Spring 3.x版本进行企业级应用程序的开发,是学习Spring技术栈的理想资源。Spring作为Java平台上的核心框架,因其强大的功能和灵活的架构设计,被广泛应用于各种规模的企业项目中。 ...

    深入解析SPRING架构与设计原理-第二版

    《深入理解Java虚拟机 JVM高级特性与最佳实践 第2版 .pdf》《深入浅出MyBatis技术原理与实战.pdf》、《MySQL技术内幕 InnoDB 第2版》、《Java并发编程的艺术.pdf》等,看后满意的话请给个5星评价吧。

    spring2-aop.pdf

    Spring框架是Java语言中最为流行的开源框架之一,其核心思想...综上所述,本书对Spring和AOP的讲解深入浅出,旨在帮助开发者了解、学会并掌握Spring框架的核心设计原理,同时也能通过阅读本书,领略到Java艺术之精妙。

Global site tag (gtag.js) - Google Analytics