spring aop

1 spring aop的目标是满足大部分的aop场景,而不是提供一个完整版的aop方案。

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html

 

2 aop的关键概念

a joint point 联接点,即一个具体的切面

b pointcut 切入点,对一组joint point的断言,用于描述哪些地方成为切面。

实例,定义一个pointcut,这里的pointcut会被advice引用,相当于指定了advice的作用域。

 

@Aspect
public class SystemArchitecture {

	@Pointcut("within(com.longji.aop..*)")
	public void inAop() {
	}

	/**
	 * A join point is in the web layer if the method is defined in a type in
	 * the com.xyz.someapp.web package or any sub-package under that.
	 */
	@Pointcut("within(com.xyz.someapp.web..*)")
	public void inWebLayer() {
	}

	/**
	 * A join point is in the service layer if the method is defined in a type
	 * in the com.xyz.someapp.service package or any sub-package under that.
	 */
	@Pointcut("within(com.xyz.someapp.service..*)")
	public void inServiceLayer() {
	}

	/**
	 * A join point is in the data access layer if the method is defined in a
	 * type in the com.xyz.someapp.dao package or any sub-package under that.
	 */
	@Pointcut("within(com.xyz.someapp.dao..*)")
	public void inDataAccessLayer() {
	}

	/**
	 * A business service is the execution of any method defined on a service
	 * interface. This definition assumes that interfaces are placed in the
	 * "service" package, and that implementation types are in sub-packages.
	 * 
	 * If you group service interfaces by functional area (for example, in
	 * packages com.xyz.someapp.abc.service and com.xyz.def.service) then the
	 * pointcut expression "execution(* com.xyz.someapp..service.*.*(..))" could
	 * be used instead.
	 * 
	 * Alternatively, you can write the expression using the 'bean' PCD, like so
	 * "bean(*Service)". (This assumes that you have named your Spring service
	 * beans in a consistent fashion.)
	 */
	@Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
	public void businessService() {
	}

	/**
	 * A data access operation is the execution of any method defined on a dao
	 * interface. This definition assumes that interfaces are placed in the
	 * "dao" package, and that implementation types are in sub-packages.
	 */
	@Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
	public void dataAccessOperation() {
	}

}
 

 

c advice 通知,分为before、after、around,分别对应方法执行前、执行后、执行前后(需要前后共享状态的时候)。切面要做的事情就在通知里定义,尽量使用最小范围的通知。通知的概念类同于拦截器,在切面拦截。

 

 

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;

@Aspect
public class AroundExample {

  @Around("com.xyz.myapp.SystemArchitecture.businessService()")
  public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
    // start stopwatch
    Object retVal = pjp.proceed();
    // stop stopwatch
    return retVal;
  }

}

 

d introduction 引入,运行时刻为某个类动态添加新行为(即新接口)

 

下例为订书服务引入新的行为IAuditable,记录和获取订书时间。

 

 

	@Test
	public void testAop() throws InterruptedException {
		BeanFactory factory = new XmlBeanFactory(new FileSystemResource("./src/test/resources/aop-context.xml"));
		BookService bookService = (BookService) factory.getBean("BookService");
		System.out.print(bookService.OrderBook("Kerluse Benn", "Professional C#"));
		printDate((IAuditable) bookService);
		Thread.sleep(10000);
		System.out.print(bookService.OrderBook("Kerluse Benn", "Expert j2ee one-on-one"));
		printDate((IAuditable) bookService);
	}

	private void printDate(IAuditable auditable) {
		auditable.setLastModifiedDate(new Date());
		System.out.println(" 订购时间为" + auditable.getLastModifiedDate());
	}

public class AuditableMixin implements IAuditable, IntroductionInterceptor {
	private Date lastModifiedDate;

	public Object invoke(MethodInvocation m) throws Throwable {
		// TODO Add your codes here
		if (implementsInterface(m.getMethod().getDeclaringClass())) {
			return m.getMethod().invoke(this, m.getArguments());
			// invoke introduced mthod,here is IAuditable
		} else {
			return m.proceed(); // delegate other method
		}
	}

	public Date getLastModifiedDate() {
		// TODO Add your codes here
		return lastModifiedDate;
	}

	public void setLastModifiedDate(Date date) {
		// TODO Add your codes here
		lastModifiedDate = date;
	}

	public boolean implementsInterface(Class cls) {
		// TODO Add your codes here
		return cls.isAssignableFrom(IAuditable.class);
	}

}
 
 

 

public interface BookService {
	public String OrderComputerMagazine(String userName, String bookName);

	public String OrderBook(String userName, String bookName);
}
 

 

public class BookServiceImpl implements BookService {
	public String OrderBook(String name, String bookName) {
		// TODO Add your codes here
		String result = null;
		result = "订购" + bookName + "成功";
		return result;
	}

	public String OrderComputerMagazine(String userName, String bookName) {
		// TODO Add your codes here
		String result = null;
		result = "订购" + bookName + "成功";
		return result;
	}
}
 

 

 

public interface IAuditable {
	void setLastModifiedDate(Date date);

	Date getLastModifiedDate();
}
  
<?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="BookServiceTarget" class="com.longji.aop.BookServiceImpl" singleton="false"/>

 <!-- introduction advice -->
 <bean id="AuditableMixin" class="com.longji.aop.AuditableMixin" singleton="false"/>

 <!-- Introduction advisor -->
 <bean id="AuditableAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor"
  singleton="false">
  <constructor-arg>
   <ref bean="AuditableMixin"/>
  </constructor-arg>
 </bean>
 
 <bean id="BookService" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="target">
   <ref bean="BookServiceTarget"/>
  </property>
  
  <property name="singleton">
   <value>false</value>
  </property>
  
  <!-- force to use cglib -->
  <property name="proxyTargetClass">
   <value>true</value>
  </property>
  
  <!-- introduction methods -->
  <property name="proxyInterfaces">
   <value>com.longji.aop.IAuditable</value>
  </property>
  
  <property name="interceptorNames">
   <list>
    <value>AuditableAdvisor</value>
   </list>
  </property>
 </bean>
</beans>

 参考(http://blogger.org.cn/blog/more.asp?name=luckystar&id=12625

 

3 spring aop支持两种声明方式,一个是@AspectJ,另一个是基于xml配置的Schema-based AOP support

 

@AspectJ的配置如下,其中concurrentOperationExecutor是一个advice,bizService是pointcut的一个联接点。

 

 

<?xml version="1.0" encoding="UTF-8"?>  
<beans default-autowire="byName" xmlns="http://www.springframework.org/schema/beans"  
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
         xmlns:aop="http://www.springframework.org/schema/aop"  
         xmlns:tx="http://www.springframework.org/schema/tx"  
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd  
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
<aop:aspectj-autoproxy/>

<bean id="concurrentOperationExecutor"
  class="com.longji.aop.ConcurrentOperationExecutor">
     <property name="maxRetries" value="3"/>
     <property name="order" value="100"/>  
</bean> 
<bean id="bizService" class="com.longji.aop.BizServiceImpl" />  
</beans> 
 

 

 

@Aspect
public class ConcurrentOperationExecutor implements Ordered {

	private static final int DEFAULT_MAX_RETRIES = 2;

	private int maxRetries = DEFAULT_MAX_RETRIES;
	private int order = 1;

	public void setMaxRetries(int maxRetries) {
		this.maxRetries = maxRetries;
	}

	public int getOrder() {
		return this.order;
	}

	public void setOrder(int order) {
		this.order = order;
	}

	@Around("com.longji.aop.SystemArchitecture.inAop()")
	public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
		int numAttempts = 0;
		PessimisticLockingFailureException lockFailureException;
		do {
			numAttempts++;
			try {
				return pjp.proceed();
			} catch (PessimisticLockingFailureException ex) {
				lockFailureException = ex;
			}
		} while (numAttempts <= this.maxRetries);
		throw lockFailureException;
	}

}

 

 

 

public interface BizService {
	public String doBiz1();

}
 

基于schema的配置如下

 

 

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

   <!-- this is the object that will be proxied by Spring's AOP infrastructure -->
   <bean id="fooService" class="com.longji.aop.DefaultFooService"/>

   <!-- this is the actual advice itself -->
   <bean id="profiler" class="com.longji.aop.SimpleProfiler"/>

   <aop:config>
      <aop:aspect ref="profiler">

         <aop:pointcut id="theExecutionOfSomeFooServiceMethod"
                    expression="execution(* com.longji.aop.FooService.getFoo(String,int))
                    and args(name, age)"/>

         <aop:around pointcut-ref="theExecutionOfSomeFooServiceMethod"
                  method="profile"/>

      </aop:aspect>
   </aop:config>

</beans>
 

 

其中fooservice是联接点,profiler是advice,pointcut直接用表达式定义了。

而这个则是把advice和pointcut关联,确定了advice的作用域

 

 

  <aop:around pointcut-ref="theExecutionOfSomeFooServiceMethod"
                  method="profile"/>

 

4 对于aop技术方案的主流选择有AspectJ(提供更全面强大的aop功能)和spring aop,spring aop又分为@AspectJ 和XML for Spring AOP(schema)

spring官方更加推荐用 @AspectJ ,因为它更加模块化,灵活,功能强大,并且比较容易迁移到 AspectJ 。

当然这两种方式也可以完美共存,他们都是基于同一套代理机制。

 

5 spring aop可以采用两套代理机制jdk内置代理或者cglib,如非必要,推荐试用jdk内置代理。因为jdk动态代理机制使用前提是委托对象实现某个接口,当委托没有实现接口的话,spring会默认使用cglib创建代理。

cglib的代理方式也由所限制,因为cglib是基于继承实现的,对于final方法无法被覆盖,因此也无法用cglib代理。另外cglib代理机制会调用两次构造方法,一次是代理对象,一次是委托对象。

如果要强制使用cglib代理,可以在schema中配置

 

<aop:config proxy-target-class="true">
    <!-- other beans defined here... -->
</aop:config>

 如果用 @AspectJ,则需配置

<aop:aspectj-autoproxy proxy-target-class="true"/>
 


 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(spring,AOP)