AOP概述
Spring AOP在运行期通过代理方式向目标类织入了增强代码。
AOP采用横向抽取机制,取代了传统纵向继承体系的重复性代码。
举例
public class UserDaoImpl implements UserDao{
public void save(){
checkprivilege();
//保存用户
...
}
}
假设要在保存用户操作之前检查用户权限,加入一个checkprivilege方法。
事实上只需要加多几行实现代码即可。
而当有上百个DaoImpl类都需要进行该操作时,修改代码的工作量就会大得夸张。
解决方案
一、纵向继承的方法
比如为所有需要加入权限检查的类,写一个共同的父类BaseDaoImpl,如:
public class BaseDaoImpl{
public void checkprivilege(){
//权限检查
...
}
}
然后让需要加入权限检查方法的DaoImpl类去继承BaseDaoImpl类,调用父类的checkprivilege()方法即可。
二、横向抽取的方法
AOP的相关术语:
Joinpoint(连接点):可以被增强的方法;
Pointcut(切入点):真正被增强的方法;
Advice(通知):要做的事情,即权限检查;
Target(目标):被增强的对象,即UserDaoImpl;
Weaving(织入):将权限校验应用到UserDaoImpl的save方法的过程;
Proxy(代理):UserDaoImpl对象加入了权限校验方法后,会产生一个新的代理对象;
Aspect(切面):切入点和通知的组合;
1、JDK动态代理
通过JDK中类来创建Proxy代理对象。
代理类
public class MyJdkProxy implements InvocationHandler{
private UserDao userDao;
//构造方法获得目标对象的引用
public MyJdkProxy(UserDao userDao){
this.userDao = userDao;
}
//产生代理对象的方法
public Object createProxy(){
//需要获取的代理类
Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this);
return proxy;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("save".equals(method.getName())){
//权限校验
.......
return method.invoke(userDao,args);
}
return method.invoke(userDao,args);
}
}
对于新生成的增强UserDao的Proxy类,实现其中的save方法都相当于调用invoke方法,所以可以在invoke方法中添加权限校验的代码。
测试类:
public class SpringDemo1 {
@Test
public void demo1(){
UserDao userDao = new UserDaoImpl();
//在save之前要做一个权限的校验
UserDao proxy = (UserDao) new MyJdkProxy(userDao).createProxy();
proxy.save();
}
}
2、CGlib生成代理
public class MyCglibProxy implements MethodInterceptor{
private UserDao userDao;
public MyCglibProxy(UserDao userDao){
this.userDao= userDao;
}
public Object createProxy(){
//1、创建核心类
Enhancer enhancer = new Enhancer();
//2、设置父类
enhancer.setSuperclass(userDao.getClass());
//3、设置回调
enhancer.setCallback(this);
//4、生成代理
Object proxy = enhancer.create();
return proxy;
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if ("save".equals(method.getName())){
//加入权限校验代码
......
return methodProxy.invokeSuper(proxy,args);
}
return methodProxy.invokeSuper(proxy,args);
}
}
测试类:
public class SpringDemo2 {
@Test
public void demo1(){
UserDao userDao = new UserDaoImpl();
UserDao proxy = (UserDao) new MyCglibProxy(userDao).createProxy();
proxy.save();
}
}