一、AOP的概念
1、AOP(Aspect Oriented Programming),面向切面编程,利用AOP可以对业务逻辑各部分进行隔离,从而降低耦合度
2、通俗地说就是,AOP可以不通过修改源代码的方式在主干功能里添加新功能
例如
这里如果要在登录功能的基础上,实现登录用户身份的判断,原始方式就是修改源代码,通过if语句进行判断,使用AOP就可以在不修改源代码的条件下添加判断功能的模块
二、AOP底层原理
1、AOP底层使用动态代理
动态代理有两种情况
(1)有接口,使用JDK动态代理
(2)没有接口,使用CGLIB动态代理
第一种 有接口情况,使用JDK动态代理
那么就是创建接口实现类代理对象,增强类的方法
在这里,接口实现类是UserDaoImpl,类的方法是login
第二种 没有接口情况,使用CGLIB动态代理
通过创建子类的代理对象,增强类的方法
三、AOP(JDK动态代理)
1、使用JDK动态代理,使用Proxy类
里面的方法创建代理对象
Proxy类
类Proxy的构造方法和普通方法
接口IncocationHandler
(1)调用newProxyInstance方法
方法的三个参数:
官方文档:
参数:
loader
- 定义代理类的类加载器
interfaces
- 代理类要实现的接口列表
h
- 指派方法调用的调用处理程序
返回:
一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
个人理解
第一个参数,类加载器
第二个参数,增强方法所在的类,这个类实现了接口,支持多个接口
第三个参数,InvocationHandler
,这是一个接口,将创建一个类实现这个接口,然后实现需要增强的功能
2、编写JDK动态代理代码
(1)创建接口,定义方法
package com.pencil.spring5;
public interface UserDao {
public int add(int a,int b);
public String update(String str);
}
(2)创建接口实现类,实现方法
package com.pencil.spring5;
public class UserDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
System.out.println("UserDao:add方法调用...");
return a+b;
}
@Override
public String update(String str) {
System.out.println("UserDao:update方法调用...");
return str;
}
}
(3)使用Proxy类创建接口代理对象
package com.pencil.spring5;
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) {
//创建接口实现类代理对象
//newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
Class[] interfaces={UserDao.class};
UserDaoImpl userDao=new UserDaoImpl();
UserDao res= (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao));
int ans=res.add(1,2);
System.out.println("answer:"+ans);
}
}
//创建代理对象代码,即方法newProxyInstance的第三个参数
class UserDaoProxy implements InvocationHandler
{
//1、把需要创建代理对象的类传进来
private UserDaoImpl userDao; //如果希望通用使用,可以用Object代替UserDaoImpl
public UserDaoProxy(UserDaoImpl userDao)
{
this.userDao=userDao;
}
//增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前执行..."+method.getName()+":传递的参数...."+ Arrays.toString(args));
//被增强的方法执行
Object obj= method.invoke(userDao,args);
//方法之后
System.out.println("方法之后执行..."+userDao);
return obj;
}
}
运行结果
main函数中主要是为了创建接口的代理类实例
创建接口的代理类实例时,使用到方法newProxyInstance
,而方法的第三个参数InvocationHandler h
,这个是指派方法调用的调用处理程序 ,而InvocationHandler h
是一个接口,因此创建一个类来实现它,那么就是实现其invoke()
方法。
实现invoke
方法,那么就要把需要创建代理对象的类传进来,因此创建一个有参构造函数,将类传进来。然后在invoke
方法中实现需要增强的方法