文章目录
Spring AOP 面向切面编程
一、AOP理念
-
面向切面(方面)编程,利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
-
简单的来说就是:用不修改源代码的方式,在主干上添加新的功能实现。
-
以登陆界面为例:
在进行成功登陆后我们添加权限判断的功能,按照原来的方式,需要修改源代码,去添加权限判断功能。但是利用AOP理念,我们添加一个权限判断模块,需要时声明即可;不需要时,也可不声明。
二、AOP底层原理 — 动态代理
① JDK动态代理 — 有接口
- 创建
接口实现类
代理对象,增强类的方法
当我们有接口UserDao
,并且含有方法login()
。一般就是通过创建其实现类重写方法进行功能实现,现在通过JDK动态代理,创建UserDao接口实现类的代理对象,在原有的功能基础之上,再添加新的功能。
② CGLIB动态代理 — 没有接口
- 创建
子类
的代理对象,增强类的方法
当我们没有接口,只有类User
,并且含有方法add()
。一般就是通过创建子类继承自User类,在方法体内部使用super关键字调用父类的方法,并对其进行完善,但是通过CGLIB动态代理,我们创建当前类的子类代理对象来进行完善。
三、AOP底层原理 — JDK动态代理实现
1、使用 JDK 动态代理,使用 Proxy 类
里面的方法创建代理对象
- (1)调用 newProxyInstance 方法
方法有三个参数:- 第一参数,类加载器
- 第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
- 第三参数,实现这个
接口 InvocationHandler
,创建代理对象,写增强的部分
2、编写 JDK 动态代理代码
- (1)创建接口,定义方法
package AOP_JDK动态代理;
public interface UserDao {
public int add(int a,int b);
public String update(String id);
}
- (2)创建接口实现类,实现方法
package AOP_JDK动态代理;
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
System.out.println("add方法执行了...");
return a+b;
}
@Override
public String update(String id) {
System.out.println("update方法执行了...");
return id;
}
}
- (3)使用 Proxy 类创建接口代理对象
package AOP_JDK动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class JDKProxy {
public static void main(String[] args) {
// 3.创建接口实现类代理对象
// 3.1 增强方法所在的类,支持多接口
Class[] interfaces = {
UserDao.class};
// 3.2 创建接口实现类对象
UserDaoImpl userDao = new UserDaoImpl();
// 3.3 创建代理对象 --- 类加载器、增强方法所在类、实现接口 InvocationHandler,创建代理对象,写增强的部分
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao));
// 通过代理对象调用增强方法
int result = dao.add(1,2);
System.out.println("result:"+result);
}
}
class UserDaoProxy implements InvocationHandler{
// 1.获取代理对象的来源 --- 通过有参构造器进行传递
private Object obj;
public UserDaoProxy(Object obj){
this.obj = obj;
}
// 2.增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 方法之前进行处理
System.out.println("方法之前进行处理..."+method.getName()+":传递的参数..."+ Arrays.toString(args));
// 被增强的方法执行
Object result = method.invoke(obj,args);
// 方法之后进行处理
System.out.println("方法之后进行处理..."+obj);
return result;
}
}
补充:
- 如果有多个方法,可以通过
method.getName()
获取调用的方法名称,然后相应的做出不同的处理。
// 2.增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("add"){
// 方法之前进行处理
System.out.println("方法之前进行处理..."+method.getName()+":传递的参数..."+ Arrays.toString(args));
// 被增强的方法执行
Object result = method.invoke(obj,args);
// 方法之后进行处理
System.out.println("方法之后进行处理..."+obj);
return result;
} else {
............
}