什么是AOP?
Spring是用来解决实际开发中的一些问题的,AOP解决了OOP中遇到的一些问题,是OOP的延续和扩展。我们可从以下三个方面来理解AOP。
-
第一个方面:扩展功能不是通过修改源代码实现的,这可通过Struts2框架中的拦截器来理解;
-
第二个方面:AOP采用横向抽取机制实现。要理解横向抽取机制,就必须先认识纵向抽取机制。例如有如下的一个类:
public class UserDao { public void save() { 添加的逻辑... } }
现在我们想在save()方法中要扩展一个功能,即日志添加功能,添加完该功能之后,就可记录在什么时候添加了哪个用户,我们想到的最原始的方法就是直接修改源代码。
public class UserDao { public void save() { 添加的逻辑... 直接写添加日志记录的代码以实现... } }
很显然这是一种愚蠢的做法,并且这儿还有一个原则:修改功能一般不是直接修改源代码来实现的。顺其自然地,咱现在就要来讲纵向抽取机制了,这时我们可编写一个BaseDao类。
public class BaseDao { public void wirtelog() { 记录日志的逻辑... } }
接下来让UserDao类继承BaseDao类,如下:
public class UserDao extends BaseDao { public void save() { 添加的逻辑... // 记录日志 super.wirtelog(); } }
这样是不是就万事大吉了呢?你懂的!因为当父类的方法名称变化时,子类调用的方法也必然要进行修改。最后,终于要讲横向抽取机制了,横向抽取机制分为两种情况,下面分别加以简单阐述。
-
有接口情况的横向抽取机制
例如有一个如下接口:public interface UserDao { public void add(); }
接口的一个实现类如下:
public class UserDaoImpl implements UserDao { public void add() { ... } }
我们现在就可以使用动态代理技术来增强类里面的方法,即创建接口的实现类代理对象,并增强UserDaoImpl类里面的add()方法。
-
无接口情况的横向抽取机制
例如有一个如下User类:public class User { public void add() { ... } }
我们现在也可以使用动态代理技术来增强类里面的方法,即创建被增强方法所在类的子类代理对象,并增强User类里面的add()方法。
-
-
第三个方面:AOP底层使用动态代理技术实现。它同样也要分为两种情况:
- 有接口情况:创建接口实现类代理对象;
- 没有接口情况:创建增强方法所在类的子类代理对象。
为什么学习AOP?
因为在不修改源代码的情况下,即可对程序进行增强,所以使用AOP咱就可以进行权限校验、日志记录、性能监控以及事务控制了。
Spring AOP的由来
AOP最早是由AOP联盟的组织提出的,他们制定了一套规范,Spring将AOP思想引入到了它的框架中,所以它也必须遵守AOP联盟的规范。
Spring AOP的底层实现原理
Spring AOP的底层用到了两种代理机制,它们分别是:
- JDK的动态代理:针对实现了接口的类产生代理,所以这种代理机制只能对实现了接口的类产生代理;
- Cglib的动态代理:针对没有实现接口的类产生代理,采用的是底层的字节码增强的技术,生成当前类的子类对象(对没有实现接口的类产生代理对象,其实就是生成那个类的子类对象)。其实它有点类似于javassist第三方代理技术。
JDK的动态代理
首先创建一个动态web项目,例如spring_demo02_aop,然后导入Spring框架相关依赖jar包,要导入哪些jar包呢?老子不想说了,自己想去。然后,在src目录下创建一个com.meimeixia.spring.demo01包,并在该包下创建一个名为UserDao的接口。
package com.meimeixia.spring.demo01;
public interface UserDao {
public void save();
public void update();
public void find();
public void delete();
}
接着,在com.meimeixia.spring.demo01包下创建以上接口的一个实现类——UserDaoImpl.java。
package com.meimeixia.spring.demo01;
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("保存用户......");
}
@Override
public void update() {
System.out.println("修改用户......");
}
@Override
public void find() {
System.out.println("查询用户......");
}
@Override
public void delete() {
System.out.println("删除用户......");
}
}
现在来了这样一个需求:我们想在UserDaoImpl实现类的save方法执行之前,进行一个权限校验。那该咋怎?可以使用JDK的动态代理来增强实现类里面的save方法,即创建该实现类的代理对象,并增强实现类里面的save方法。说干就干,在com.meimeixia.spring.demo01包下编写一个名为JDKProxy的类,在该类中使用JDK的动态代理机制来对UserDaoImpl实现类产生代理对象。
package com.meimeixia.spring.demo01;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 使用JDK的动态代理机制来对UserDao产生代理
* @author liayun
*
*/
public class JDKProxy implements InvocationHandler {
//得将被增强的对象传递到我们的代理当中
private UserDao userDao;//被增强的对象
public JDKProxy(UserDao userDao) {
this.userDao = userDao;
}
/*
* 产生UserDao代理的方法
*/
public UserDao createProxy() {
UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(), this);
return userDaoProxy;