#前言
这个项目是基于JSpring IoC
的,所以在看下去之前,你要确保看过之前实现JSpring IoC
的文章(这些文章在我的博客分类JSpring IoC
),不然也不看不出什么意思来,就不用浪费时间往下看了。
在做这个项目的时候发生了一件有趣的事,我发现了JSpring IoC
的一个Bug……,在 自己实现Spring IoC容器(四)IoC容器的Bug对这个Bug进行了介绍,也没什么,就是写错了一句代码。有趣的是我的那篇文章被推荐到了首页!!
我真是不知道他们是以什么标准推荐的,我觉得那篇文章真的是没什么出彩的地方。
啥也不说了,继续撸起袖子干吧
#搭建环境
上面我说到这项目是基于JSpring IoC
的,所以我先把它给弄好。
- 新建一个
Java Project
,命名为JSpring AOP
,我的工作空间字符编码默认是UTF-8
,所以你们Clone下来后乱码的话就把项目字符编码改成UTF-8
。 - 把JSpring-IoC的代码Clone或则Download下来。考虑到别人的IDE环境跟我的未必相同,所以在提交项目的时候我是忽略eclipse配置文件如
.project
和.classpath
等文件的,这样子你就不能通过eclipse直接引入该工程了。所以你需要在你的IDE(可以是别的)新建一个工程,工程名随意,然后将JSpring-IoC
的代码拷贝到相应的位置。 - 将
lib
包下的jar
包Build Path
。 - 删除
JSpring-IoC
一些跟测试相关的东西,只保留功能代码。把源码文件test
删掉,等下要再重新创建;删除edu.jyu.bean
包,这也是测试用到的;删除applicationContext.xml
中有关bean
的配置,保留根标签beans
。
上面4步就可以将环境搭建起来了。
现在还需要一些准备知识
#知识准备
我要实现的是JSpring AOP
,那么你得有Spring AOP 的相关知识。
在Spring中如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP,如果目标对象没有实现接口,必须采用CGLib(Code Generation Library)方式。
关于这些动态代理的知识可以看Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM),写的很好
至于Spring AOP的一些使用方法,还不了解的还是去找本书来看吧
#要实现的东西
我先用Spring传统的AOP方式(即没有用AspectJ)演示一个例子,搭建Spring环境什么的我就在这介绍了,直接开干
(1)先准备好目标对象相关类和接口
UserDao接口
package edu.jyu.dao;
public interface UserDao {
public void add(String user);
}
UserDaoImpl类,实现了UserDao接口
package edu.jyu.dao;
public class UserDaoImpl implements UserDao{
@Override
public void add(String user) {
System.out.println("add "+user);
}
}
(2)编写增强代码,即通知,在此定义一个前置通知,其实还有各种什么后置通知环绕通知等东西,在这里就不去介绍了,自己去了解吧。
package edu.jyu.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("-----------前置通知-----------");
System.out.println("方法:" + method.getName());
System.out.println("参数" + args);
System.out.println("目标对象" + target);
System.out.println("-----------前置通知-----------");
}
}
(3)编写配置文件applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 目标对象 -->
<bean id="userDao" class="edu.jyu.dao.UserDaoImpl"></bean>
<!-- 前置通知 -->
<bean id="beforeAdvice" class="edu.jyu.advice.MyBeforeAdvice"></bean>
<!-- 配置生成代理对象 -->
<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理的目标对象 -->
<property name="target" ref="userDao" />
<!-- 代理要实现的接口 -->
<property name="proxyInterfaces" value="edu.jyu.dao.UserDao" />
<!-- 需要织入目标的通知 -->
<property name="interceptorNames" value="beforeAdvice" />
</bean>
</beans>
(4)编写测试类
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import edu.jyu.dao.UserDao;
public class TestProxy {
@Test
public void test() {
ApplicationContext atx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//注意这里要获取的是userDaoProxy不是userDao
UserDao userDao = (UserDao) atx.getBean("userDaoProxy");
userDao.add("Jason");
System.out.println(userDao.getClass());
}
}
运行结果
-----------前置通知-----------
方法:add
参数[Ljava.lang.Object;@64485a47
目标对象edu.jyu.dao.UserDaoImpl@7a30d1e6
-----------前置通知-----------
add Jason
class com.sun.proxy.$Proxy4
可以看出执行顺序是
- 执行前置通知
MyBeforeAdvice
中的before
方法 - 执行目标对象中的
add
方法
最后输出的是代理类。
到此一个,Spring AOP的例子就展示完毕,我自己实现的AOP功能就是仿造上面例子的,只不过进行了一些改动。
搭建好的JSpring AOP项目已经上传到Github上
https://github.com/HuangFromJYU/JSpring-AOP