spring最核心的也就属ioc和aop了,虽然知道ioc和aop的原理,但在项目中只用到了ioc,aop没用到,所以这里对aop进行一下总结。
spring aop英文全名Aspect Orient Programming 也就是面向方面编程,它是对面向对象编程的一种补充,被专门用来处理系统中分布于各个模块中的交叉关注点的问题,例如在javaee应用中aop常被用来处理一些具有横切性质的系统级服务如事务管理,安全检查,缓存,对象池管理等。AOP框架通过自动生成代理来实现业务的扩充,spring AOP有两种生成代理的方式,一种是JDK的动态代理,一中时CGLIB的,这两种的区别在于如果目标对象实现了接口,spring AOP就会使用jdk的动态代理,如果目标对象没有实现接口,它就会使用CGLIB的。关于jdk的动态代理在设计模式系列的文章中已经详述,这里就不多说,下面我们来使用spring aop来完成功能的扩充。
首先导入spring的jar包,这里直接截图:
因为我是先把spring和struts2整合了一下才测试的,所以里面包含了一些struts2的jar包,这里只看spring 的
实现aop必须的包:
1、aopalliance.jar
AOP Alliance(http://aopalliance.sourceforge.net/) 是个联合的开源协作组织,在多个项目间进行协作以期提供一套标准的AOP Java接口(interface)。 Spring AOP就是基于AOP Alliance标准API实现的。如果你打算使用Spring的AOP或基于AOP的任何特性,只需这个JAR文件。
2、aspectjrt.jar和aspectjweaver.jar,如果你的目标对象没有实现目标接口,你还得导入cglib的jar包,这里只是测试实现接口的目标对象,所以不导入了,其他一些必要的spring包比如核心包等大家应该都知道。
接下来我们在配置文件spring.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
classpath:/org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
classpath:/org/springframework/context/config/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
classpath:/org/springframework/aop/config/spring-aop-3.0.xsd
">
<!-- 指定自动搜索 Bean 组件、自动搜索方面类 -->
<context:component-scan base-package="com.dxy.service.impl,com.dxy.test">
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>
<!-- 启动@Aspect支持 -->
<aop:aspectj-autoproxy/>
</beans>
对于spring.xml文件中的以这样的方式引入xsd文件,是因为网速慢,所以解析xsd文件出错,不得不用本地的xsd文件,具体原因见:
http://blog.csdn.net/legendj/article/details/9950963
接着创建接口UserServiceI.java:
package com.dxy.service;
public interface UserServiceI {
public String add();
}
创建实现:
package com.dxy.service.impl;
import org.springframework.stereotype.Service;
import com.dxy.service.UserServiceI;
@Service("userService")
public class UserServiceImpl implements UserServiceI {
@Override
public void add() {
System.out.println("hello world");
}
}
接着定义一个方面,并使用spring AOP的Around增强处理:
package com.dxy.test;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
//定义一个方面
@Aspect
public class AroundAdviceTest {
@Around("execution(* com.dxy.service.impl.*.*(..))")
public void log(ProceedingJoinPoint jp) {
System.out.println("test add start");
try {
jp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("test add end");
}
}
ok,我们在客户端可以调用了:
package com.dxy.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.dxy.service.UserServiceI;
public class MainTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring.xml");
UserServiceI userService = (UserServiceI)ac.getBean("userService",UserServiceI.class);
System.out.println(userService.getClass());
userService.add();
}
}
运行结果:
这样就成功的在add方法前后加上了日志处理,我们通过打印userService的类型得到的是一个代理类class $Proxy8如果使用cglib的话就会生成一个cglib的代理。通过以上示例我们可以知道AOP 代理其实是由 AOP 框架动态生成的一个对象,该对象可作为目标对象使用。AOP 代理包含了目标对象的全部方法,但 AOP 代理中的方法与目标对象的方法存在差异:AOP 方法在特定切入点添加了增强处理,并回调了目标对象的方法。