SpingAOP两种配置方式的简单实例

Aspect-Oriented Programming(面向切面编程),以一种全新的方式思考程序的结构,这补充了Object-Oriented Programming(面向方法编程)范式的不足。OOP主要的模块单元是类,然而,AOP主要的模块单元是切面。切面允许关注诸如横跨不同类型和对象的业务管理这样的关注点。(这些关注点在AOP学术领域通常被称为横切)

(以上定义来自SpingAOP官方网站点击打开链接)

下面分别以纯AspectJ注解和XML配置两种配置方式实现一个简单的例子

一 AspectJ注解方式

1.先定义一个接口,用来获取一个简单对象

package spring;

public interface PersonService {
	Person  getPerson(String fooName, int age);
}

2.定义一个实现该接口的类

package spring;

public class DefaultPersonService   implements PersonService{
	
	public DefaultPersonService(){
		
	}

	@Override
	public Person getPerson(String name, int age) {
		return new Person(name,age);
	}

}
3.其中Person类的定义如下

package spring;

public class Person {

	private String name;
	private int age;
	
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public String toString(){
		//格式化输出
		return "this is "+this.name+", age is"+this.age;
	}
	
}
4.为了统一管理项目的所有切点(Pointcut),最好将全部切点的定义统一放到同一个类文件里,如下所示

package spring;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class SimplePointcut {

	 @Pointcut("execution(* spring.PersonService.getPerson(String,int))")//切点表达式
	 public void inServiceLayer() {//切点签名
		 //空方式实现即可
	 }
	 
}
5. 对于同一个切点,允许同时为其配置多个通知(Advice),如下

package spring;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class SimpleAdvice {
	@Before("spring.SimplePointcut.inServiceLayer()")//指向指定的切点签名
	public void beforeLog() {
		System.out.println("=====================================");
		System.out.println("Aop: do before in service layer");
		System.out.println("=====================================");
	}

	@After("spring.SimplePointcut.inServiceLayer()")
	public void afterLog() {
		System.out.println("=====================================");
		System.out.println("Aop: do after in service layer");
		System.out.println("=====================================");
	}
}

6.定义一个配置类来实现IOC容器对Bean对象的管理,同时,用main()方法来打印结果
package spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;


@Configuration
@EnableAspectJAutoProxy
public class Application {  
	@Bean(name="personService")
	public DefaultPersonService defaultPersonService(){
		return  new DefaultPersonService();
	}

	@Bean
	public SimplePointcut simplePointcut(){
		return new SimplePointcut();
	}

	@Bean
	public SimpleAdvice simpleAdvice(){
		return new SimpleAdvice();
	}


	public static void main(String[] args)  throws Exception{  

		ApplicationContext ctx = new AnnotationConfigApplicationContext(Application.class);
		PersonService foo = (PersonService) ctx.getBean(PersonService.class);
		Person p =  foo.getPerson("Lily", 12);
		Thread.sleep(100);//模拟其他业务逻辑
		System.err.println(p);

	}  
} 

7.程序运行打印结果,如下图

SpingAOP两种配置方式的简单实例_第1张图片

二,XML配置方式

1. DefaultPersonServicePerson,PersonService类的定义不变,通知类的定义改为以下方式

package spring;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;

public class XMLAdvice {
	
	public void beforeLog(JoinPoint joinPoint) {
		System.out.println("=====================================");
		System.out.println("Aop: do before in service layer");
		System.out.println("=====================================");
	}

	public void afterLog(JoinPoint joinPoint) {
		System.out.println("=====================================");
		System.out.println("Aop: do after in service layer");
		System.out.println("=====================================");
	}
	
	//Around通知的参数为ProceedingJoinPoint,而不是JoinPoint
	public Object  aroundLog(ProceedingJoinPoint call) throws Throwable {
		StopWatch clock = new StopWatch("aroundLog " );
		try {
			clock.start(call.toShortString());
			return call.proceed();
		} finally {
			clock.stop();
			System.out.println(clock.prettyPrint());
		}
		
	}
}
2.xml的配置文件如下
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
	<bean id="personService" class="spring.DefaultPersonService" />

	<bean id="adviceconfig" class="spring.XMLAdvice" />
	<aop:config>
		<aop:aspect id="aspect" ref="adviceconfig">

			<aop:pointcut id="theExecutionOfSomeFooServiceMethod"
				expression="execution(* spring.PersonService.getPerson(String,int))" />

			<aop:before pointcut-ref="theExecutionOfSomeFooServiceMethod"
				method="beforeLog" />
			<aop:after pointcut-ref="theExecutionOfSomeFooServiceMethod"
				method="afterLog" />

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

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

</beans>
3 . 示例代码如下

package spring;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Application {  

	public static void main(String[] args)  throws Exception{  

		  BeanFactory ctx = new ClassPathXmlApplicationContext("daos.xml");
		  PersonService foo = (PersonService) ctx.getBean("personService");
		  Person p =       foo.getPerson("Pengo", 12);
		  Thread.sleep(100);//模拟其他业务逻辑
		  System.err.println(p);

	}  
} 

总结(关于两种方式的优劣比较):


xml优点:

切面、切点、通知等配置都写在一个或几个xml配置文件里,结构清晰,便于管理;

兼容旧项目

xml缺点:

配置比较麻烦(除非安装相应的配置插件)

AspectJ注解优点:

定义简单,只需要用相应的注解修饰;

自由组合切点;

能够同时被 Spring AOP 和 AspectJ理解,能够方便切换到AspectJ框架

AspectJ注解缺点:

必须使用Java5版本及以后版本;

切面、切点、通知的定义位置比较零散


最后,总结一下,这两种方式互相补充,一方的优点恰好是另一方的劣处。在实际项目中,可以同时采用两种方式混合配置。总之,

平衡才是王道!!

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