鸣谢:感谢北京尚学堂马士兵老师的视频教程。
实现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):