【Spring专题-③】AOP浅析(二)

这篇算不上原创,内容主要来自Spring reference 及 网络
在AOP浅析(一)基础上,继续写了这篇。

AOP浅析(一)是主要讲基础原理,这篇是在基础上讲一些常见应用。

零 概述

AOP的作用

AOP is used in the Spring Framework to...
• ... provide declarative enterprise services, especially as a replacement for EJB declarative services(EJB声明式服务). The
most important such service is declarative transaction management.
• ... allow users to implement custom aspects, complementing their use of OOP with AOP.
If you are interested only in generic declarative services or other pre-packaged declarative middleware
services such as pooling, you do not need to work directly with Spring AOP, and can skip most of this
chapter.

一 Pointcut

1. Declaring a pointcut
@Pointcut("execution(* transfer(..))")// the pointcut expression
private void anyOldTransfer() {}// the pointcut signature


2 Supported Pointcut Designators

• execution

• within

• this

• target

• args

• @target

• @args

• @within

• @annotation


3 Combining pointcut expressions

Pointcut expressions can be combined using '&&', '||' and '!'. It is also possible to refer to pointcut
expressions by name.

@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}
@Pointcut("within(com.xyz.someapp.trading..*)")
private void inTrading() {}
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}

4 Sharing common pointcut definitions

/**
* 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 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() {}


For example, to make the service layer transactional, you could write:

<aop:config>
<aop:advisor
pointcut="com.xyz.someapp.SystemArchitecture.businessService()"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>


5 Examples

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

• the execution of any method defined by the AccountService interface:

execution(* com.xyz.service.AccountService.*(..))

• the execution of any method defined in the service package:

execution(* com.xyz.service.*.*(..))

• any join point (method execution only in Spring AOP) within the service package:

within(com.xyz.service.*)

• any join point (method execution only in Spring AOP) where the proxy implements the
AccountService interface:

this(com.xyz.service.AccountService)

• any join point (method execution only in Spring AOP) where the target object implements the
AccountService interface:

target(com.xyz.service.AccountService)


• any join point (method execution only in Spring AOP) where the target object has an
@Transactional annotation:

@target(org.springframework.transaction.annotation.Transactional)


二 Advice

1 Declaring advice

a Before advice

Before advice is declared in an aspect using the @Before annotation:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}

If using an in-place pointcut expression we could rewrite the above example as:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}

b After returning advice

和before差不多


c After throwing advice


d After (finally) advice


e Around advice

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;
}
}

f Advice parameters

f.1 Access to the current JoinPoint

f.2 Passing parameters to advice

@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)")
public void validateAccount(Account account) {
// ...
}
f.3 Advice parameters and generics

f.4 Determining argument names

f.5 Proceeding with arguments

g Advice ordering


2 Example


三 Schema-based AOP support
1 Declaring an aspect

<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>

2 Declaring a pointcut

<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
</aop:config>
For example, the following pointcut collects the 'this' object as the join point context and passes it to advice:

<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..)) && this(service)"/>
<aop:before pointcut-ref="businessService" method="monitor"/>
...
</aop:aspect>
</aop:config>

3 Declaring advice

3.1 Before advice

<aop:aspect id="beforeExample" ref="aBean">
<aop:before
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>

or

<aop:aspect id="beforeExample" ref="aBean">
<aop:before
pointcut="execution(* com.xyz.myapp.dao.*.*(..))"
method="doAccessCheck"/>
...
</aop:aspect>

3.2 After returning advice

<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>

Just as in the @AspectJ style, it is possible to get hold of the return value within the advice body. Use the
returning attribute to specify the name of the parameter to which the return value should be passed:

<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
returning="retVal"
method="doAccessCheck"/>
...
</aop:aspect>

For example, the method signature may be declared as:

public void doAccessCheck(Object retVal) {...

3.3 After throwing advice

After throwing advice executes when a matched method execution exits by throwing an exception

<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
method="doRecoveryActions"/>
...
</aop:aspect>

Just as in the @AspectJ style, it is possible to get hold of the thrown exception within the advice body.
Use the throwing attribute to specify the name of the parameter to which the exception should be passed:

<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
throwing="dataAccessEx"
method="doRecoveryActions"/>
...
</aop:aspect>

The doRecoveryActions method must declare a parameter named dataAccessEx.

For example, the method signature may be declared as:

public void doRecoveryActions(DataAccessException dataAccessEx) {...

3.4 After (finally) advice

<aop:aspect id="afterFinallyExample" ref="aBean">
<aop:after
pointcut-ref="dataAccessOperation"
method="doReleaseLock"/>
...
</aop:aspect>


3.5 Around advice

Around advice is declared using the aop:around element. The first parameter of the advice method must be of type ProceedingJoinPoint.

<aop:aspect id="aroundExample" ref="aBean">
<aop:around
pointcut-ref="businessService"
method="doBasicProfiling"/>
...
</aop:aspect>

advice 在Java中的定义

public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}

3.6 Advice parameters 

arg-names

<aop:before
pointcut="com.xyz.lib.Pointcuts.anyPublicMethod() and @annotation(auditable)"
method="audit"
arg-names="auditable"/>

The arg-names attribute accepts a comma-delimited list of parameter names.

arg-names 接受一个以逗号分隔的参数列表

For Example:

join point

package x.y.service;
public interface FooService {
Foo getFoo(String fooName, int age);
}
public class DefaultFooService implements FooService {
public Foo getFoo(String name, int age) {
return new Foo(name, age);
}
}

around service

package x.y;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
public class SimpleProfiler {
public Object profile(ProceedingJoinPoint call, String name, int age) throws Throwable {
StopWatch clock = new StopWatch(
"Profiling for '" + name + "' and '" + age + "'");
try {
clock.start(call.toShortString());
return call.proceed();
} finally {
clock.stop();
System.out.println(clock.prettyPrint());
}
}
}

XML configuration

<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="x.y.service.DefaultFooService"/>
<!-- this is the actual advice itself -->
<bean id="profiler" class="x.y.SimpleProfiler"/>
<aop:config>
<aop:aspect ref="profiler">
<aop:pointcut id="theExecutionOfSomeFooServiceMethod"
expression="execution(* x.y.service.FooService.getFoo(String,int))
and args(name, age)"/>
<aop:around pointcut-ref="theExecutionOfSomeFooServiceMethod"
method="profile"/>
</aop:aspect>
</aop:config>
</beans>

测试类:
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import x.y.service.FooService;
public final class Boot {
	public static void main(final String[] args) throws Exception {
		BeanFactory ctx = new ClassPathXmlApplicationContext("x/y/plain.xml");
		FooService foo = (FooService) ctx.getBean("fooService");
		foo.getFoo("Pengo", 12);
	}
}

3.7 Advisors

The concept of "advisors" is brought forward from the AOP support defined in Spring 1.2 and does not have a direct equivalent in AspectJ。

Spring 2.0 supports the advisor concept with the <aop:advisor> element。

例:

<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:advisor
pointcut-ref="businessService"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>


四 For Example

例子来源地址

http://sling2007.blog.163.com/blog/static/8473271320121134391194/

service:

package com.mydemo.service;

public interface StuService {
	public String addStu(String name, int age);
	public String delStu(String name, int age);
	public String queryStu(String name);

}

servcieImpl

package com.mydemo.service;

public class StuServiceImpl implements StuService {

	@Override
	public String addStu(String name, int age) {
		// TODO Auto-generated method stub
		System.out.println(name + "=========add==========" + age);
		return null;
	}

	@Override
	public String delStu(String name, int age) {
		// TODO Auto-generated method stub
		System.out.println(name + "=========del==========" + age);
		return null;
	}

	@Override
	public String queryStu(String name) {
		// TODO Auto-generated method stub
		System.out.println(name+"=======query========");
		return null;
	}

}

aop的拦截方法:

package com.mydemo.advice;

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

@Component
@Aspect
public class AspectDemo {
	//被拦截的方法格式是:返回值   包.包.类.方法(参数)
	@Before("execution (* com.mydemo.service.*.add*(..))")
	public void beforeAdvice() throws Throwable{
		System.out.println("@Before Advice is executed!==========>");
	}
	
	@Around("execution (* com.mydemo.service.*.del*(..))")
	public Object aroundAdvice(ProceedingJoinPoint jp) throws Throwable {
		Object object = jp.proceed();
		Object[] args = jp.getArgs();
		for (Object obj : args) {
			System.out.println("参数值:" + obj);
		}
		System.out.println("后处理切入----------"
				+ jp.getTarget().getClass().getName() + "----"
				+ jp.getSignature().getName());
		return object;
	}

}

spring3的配置文件application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:context="http://www.springframework.org/schema/context"
		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
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<!-- 自动扫描被注解的类 -->
	<context:component-scan base-package="com.mydemo.*" />
	<!--启动spring的aop自动代理 -->
 	<aop:aspectj-autoproxy />
 	<!-- 定义一个测试bean -->
 	<bean id="stuService" class="com.mydemo.service.StuServiceImpl"></bean>

</beans>

4 测试类

package com.mydemo.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mydemo.service.StuService;

public class AppDemo {
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
		StuService stu = (StuService) ctx.getBean("stuService");
		stu.addStu("bruce", 20);
		System.out.println("##############################################");
		stu.delStu("focus", 18);
		System.out.println("##############################################");
		stu.queryStu("Mary");
	}

}

5 引入的jar包

除了spring3的jar之外,不要忘记引入红框中的jar,aspectjrt.jar、aspectweaver.jar、aopalliance-1.0.jar



6 输出结果




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值