鸣谢:感谢北京尚学堂马士兵老师的视频教程。
实现AOP需要加入aspectj的两个JAR包:aspectjweaver.jar, aspectjrt.jar
当要对没有实现接口的类实现动态代理,需要引入CGLIB的JAR包:cglib-nodep-2.1_3.jar
AOP的Annotation实现方式:
必须在配置文件中加入<aop:aspectj-autoproxy/>标签,加入该标签后才能在源代码中使用Annotation的方式实现动态代理。
要想使用<aop:aspectj-autoproxy/>标签,必须在beans标签中加入以下属性:
xmlns:aop=http://www.springframework.org/schema/aop http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
具体实现代码段如下:
beans.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- spring2.5配置文件固定写法 --> <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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- 加入此配置就可以在源码中写Annotation(注解),注解编程 --> <context:annotation-config /> <!-- 使用此配置代码,spring会自动扫描com.yusj包下的所有带@component注解的Class文件 @Component包括:@controller,@service,@repository和@component 当分不清楚Class具体要做什么工作时,可以统一写成@component. @controller:一般写在控制层。 @service:一般写在服务层。 @repository:一般写在持久层,也就是DAO。 @component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/> --> <context:component-scan base-package="com.yusj" /> <!-- 加入此配置就可以在源代码中写关于AOP(aspectj)的Annotation(注解)了。 --> <aop:aspectj-autoproxy /> </beans>
LogInterceptor.java(织入类):
package com.yusj.aop;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* 为某些切入点植入新的方法
* 必要条件:
* 1. 源方法与目标方法必须都被Spring容器管理
* 2. 在类名上方加入@Component和@Aspect注解
* @author yushaojian
*
*/
@Component
@Aspect
public class LogInterceptor {
/**
* 在com.yusj.dao.IUserDAO.save方法执行前,执行doBefore方法
*/
@Before("execution(public void com.yusj.dao.IUserDAO.save(com.yusj.model.User))")
public void doBefore(){
System.out.println("save start ...") ;
}
/**
* 在com.yusj.dao包下所有类的所有方法正式执行之后再执行afterReturning方法
*/
@AfterReturning("execution(* com.yusj.dao..*.*(..))")
public void afterReturning(){
System.out.println("save after returning ...") ;
}
}
Test.java:
package com.yusj.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import com.yusj.model.User;
import com.yusj.service.IUserService;
public class Test {
public static void main(String[] args) {
/**
* Spring提供的读取配置文件方法,此处推荐使用ApplicationContext而非BeanFactory.
* beans配置文件默认读取src根目录文件名相同的XML文件
* 如果需要放在特殊的位置,那么需要指定具体路径,比如:com/yusj/xml/beans.xml
*
*/
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
/**
* 获取UserServiceImpl.java中利用@Component("usi")自动装载的bean
*
*/
IUserService service = (IUserService) ctx.getBean("usi");
// 初始化用户并赋值
User u = new User();
u.setUsername("张三");
u.setPassword("zhangsan");
// 添加用户测试
service.add(u);
/**
* 输出结果:
* save start ...
* user save success...
* User [username=张三, password=zhangsan]
* save after returning ...
*/
}
}
XML配置实现:
beans.xml(去掉<aop:aspectj-autoproxy/>标签):
<?xml version="1.0" encoding="UTF-8"?> <!-- spring2.5配置文件固定写法 --> <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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- 加入此配置就可以在源码中写Annotation(注解),注解编程 --> <context:annotation-config /> <!-- 使用此配置代码,spring会自动扫描com.yusj包下的所有带@component注解的Class文件 @Component包括:@controller,@service,@repository和@component 当分不清楚Class具体要做什么工作时,可以统一写成@component. @controller:一般写在控制层。 @service:一般写在服务层。 @repository:一般写在持久层,也就是DAO。 @component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/> --> <context:component-scan base-package="com.yusj" /> <!-- 定义切面类的Bean --> <bean id="logInterceptor" class="com.yusj.aop.LogInterceptor" /> <!-- 配置AOP --> <aop:config> <!-- 定义全局的pointcut,所有的代理过滤条件都参照此pointcut --> <aop:pointcut expression="execution(public void com.yusj.dao.IUserDAO.save(com.yusj.model.User))" id="userDAOPointcut"/> <!-- 把标准Bean与AOP-aspect做关联,标准Bean就成为具有aspect(切面织入)功能的Bean --> <aop:aspect id="logAspect" ref="logInterceptor"> <!-- pointcut-ref : 过滤需要代理的方法的切入点,此例中是为IUserDAO.save方法加入代理. 关联方法:通过pointcut-ref属性,找到aop:pointcut中的expression属性来实现过滤. method : 在pointcut-ref所指定方法执行前,执行com.yusj.aop.LogInterceptor.doBefore方法. 关联方法:因为aop:before标签是在aop:aspect标签中,所以通过aop:aspect的ref属性找到Bean(com.yusj.aop.LogInterceptor). --> <aop:before method="doBefore" pointcut-ref="userDAOPointcut"/> </aop:aspect> </aop:config> </beans>
LogInterceptor.java(去掉所有Annotation,在XML中定义Bean):
package com.yusj.aop;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* 用XML实现,切面类不用做特殊处理
* @author yushaojian
*
*/
public class LogInterceptor {
public void doBefore(){
System.out.println("save start ...") ;
}
public void afterReturning(){
System.out.println("save after returning ...") ;
}
}
Test.java:
package com.yusj.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import com.yusj.model.User;
import com.yusj.service.IUserService;
public class Test {
public static void main(String[] args) {
/**
* Spring提供的读取配置文件方法,此处推荐使用ApplicationContext而非BeanFactory.
* beans配置文件默认读取src根目录文件名相同的XML文件
* 如果需要放在特殊的位置,那么需要指定具体路径,比如:com/yusj/xml/beans.xml
*
*/
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
/**
* 获取UserServiceImpl.java中利用@Component("usi")自动装载的bean
*
*/
IUserService service = (IUserService) ctx.getBean("usi");
// 初始化用户并赋值
User u = new User();
u.setUsername("张三");
u.setPassword("zhangsan");
// 添加用户测试
service.add(u);
/**
* 输出结果:
* save start ...
* user save success...
* User [username=张三, password=zhangsan]
*/
}
}
eclipse项目导出见附件(Export -> General -> File System):