Aop概念
- 面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提供程序的可重用性,同时提高了开发的效率
- 通俗描述:不通过修改源代码的方式,在主干功能里面添加新功能
AOP术语
- 连接点
- 类里面哪些方法可以被增强,这些方法被称为连接点
- 切入点
- 实际被真正增强的方法,称为切入点
- 通知(增强)
- 实际增强的逻辑部分称为通知(增强)
- 通知有多种类型
- @Before前置通知:方法执行之前通知
- @AfterReturn后置通知:方法执行之后通知有异常不会执行
- @Around环绕通知:方法执行前后通知,如果有异常,方法之后不执行
- @AfterThrowing:异常通知:方法出现异常通知
- @After最终通知:类似于finally,不管有没有异常都会执行
- 切面
- 把通知应用到切入点过程叫做切面
AOP操作(准备)
-
Spring框架一般是基于AspectJ实现AOP操作
- AspectJ不是spring的组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作
-
基于注解方式实现(使用)
-
切入点表达式
- 作用:知道对哪个类里面的哪个方法进行增强
- 语法结构
- execution([][][权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))
- 对com.niyp.BookDao类里面的add进行增强
- execution(* com.niyp.BookDao.add(…) )
- 省略返回类型
- 对com.niyp.BookDao类里面的所有的方法进行增强
- execution(* com.niyp.BookDao.*(…) )
- 省略返回类型
- 对com.niyp.包里面所有的类,类里面的所有的方法进行增强
- execution(* com.niyp.* . * (…) )
- 省略返回类型
-
可以对相同的切入点表达式做一个抽取
-
如果有多个增强类对同一个方法进行增强,设置增强类优先级
- 在增强类上面增加注解@Order(数字),数字越小,越先执行
-
注意:需要在启动类上增加@EnableAspectJAutoProxy注解
AOP底层原理
AOP的底层使用动态代理
- 动态代理有两种:JDK代理和CGLB代理
JDK代理
//java.lang.reflect.Proxy#newProxyInstance
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
参数介绍
1.loader 类加载器
2.interfaces 增强方法所在的类,这个类实现的接口,支持多个接口
3.invocationHandler 实现这个接口InvocationHandler,创建代理对象,写增强的方法
代码演示
- 创建接口
public interface UserDao {
public int add(int a, int b);
public String update(String id);
}
- 创建接口实现类,实现方法
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public String update(String id) {
return 1+"";
}
}
- 使用Proxy类创建接口代理对象
public class CustomInvocationHandler<T> implements InvocationHandler {
//1. 把创建的是谁的代理对象,把谁传递进来
private T t;
public CustomInvocationHandler(T t) {
this.t = t;
}
//增强的luo'ji
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法执行之前..."+method.getName()+":传递的参数:"+ Arrays.toString(args));
//被增强的方法
Object result = method.invoke(t, args);
//方法之后
System.out.println("方法执行之后..." + result);
return result;
}
}
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = new Class[]{UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
//返回代理对象
UserDao proxyInstance = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new CustomInvocationHandler(userDao));
int add = proxyInstance.add(1, 2);
System.out.println("=========>" + add);
}
}
CGLB代理
- 代码演示