AOP:Aspect Oriented Programming
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合性降低,提高程序的可重用性的,同时提高开发效率。
AOP作用及优势
作用:在程序运行期间,不修改源码对已有方法进行增强
优势:减少重复代码,提高开发效率,维护方便
原理:采用动态代理的方式(基于接口的动态代理和基于子类的动态代理)
/**
* 一个演员
*/
public class Actor implements IActor {
/**
* 基本的表演
*
* @param money
*/
public void basicAct(float money) {
System.out.println("拿到钱,开始基本的表演:" + money);
}
/**
* 危险的表演
*
* @param money
*/
public void dangerAct(float money) {
System.out.println("拿到钱,开始危险的表演:" + money);
}
}
------------------
基于接口的动态代理
/**
* 模拟一个剧组
*/
public class Client {
public static void main(String[] args) {
final Actor actor = new Actor();
// actor.basicAct(100f);
// actor.dangerAct(500f);
/**
* 动态代理:
* 作用:不改变源码的基础上,对己方已有的方法增强。(它是AOP思想的实现技术)
* 分类:
* 基于接口的动态代理:
* 要求:被代理类最少实现一个接口
* 提供者:JDk官方
* 涉及的类:Proxy
* 创建代理对象的方法:newProxyInstance(ClassLoader,Class[],InvocationHandler)
* 参数含义:
* ClassLoader:类加载器。和被代理对象使用相同的类加载器。一般都是固定写法。
* Class[]:字节码数组。被代理类实现的接口。(要求被代理对象和代理对象具有相同的行为)。一般都是固定写法。
* InvocationHandler:它是一个接口,就是用于我们提供增强代码的。我们一般都是写一个该接口的实现类。实现类可以是匿名内部类。
* 它的含义是:如何代理。此处的代码只能是谁用谁提供
* 策略模式:
* 使用要求:数据已经有了
* 目的明确
* 达成目标的过程就是策略。
* 在dbutils中的ResultSetHandler就是策略模式的具体应用
* 基于子类的动态代理
*/
IActor proxyActor = (IActor) Proxy.newProxyInstance(actor.getClass().getClassLoader(),
actor.getClass().getInterfaces(),
new InvocationHandler() {
/**
*
* 执行被代理对象的任何方法都会经过该方法,该方法有拦截的功能
* 方法的参数:
* Object proxy:代理对象的引用。不一定每次都会有
* Method method:当前执行的方法
* Object[] args:当前执行方法所需的参数
* 返回值:
* 当前执行方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object rtValue = null;
//1.取出执行方法中的参数
Float money = (Float)args[0];
//2.判断当前执行的是什么方法
if("basicAct".equals(method.getName())){
//基本演出
if(money > 10000){
//执行方法(开始表演)
rtValue = method.invoke(actor, money/2);
}
}
if("dangerAct".equals(method.getName())){
//危险演出
if(money > 50000){
//执行方法
rtValue = method.invoke(actor, money/2);
}
}
return rtValue;
}
});
proxyActor.basicAct(20000);
proxyActor.dangerAct(60000);
}
}
-------------
基于子类的动态代理
/**
* 模拟一个剧组
*/
public class Client {
public static void main(String[] args) {
final Actor actor = new Actor();
// actor.basicAct(100f);
// actor.dangerAct(500f);
/* *
* 动态代理:
* 作用:不改变源码的基础上,对己方已有的方法增强。(它是AOP思想的实现技术)
* 分类:
* 基于接口的动态代理:
*
* 基于子类的动态代理:
* 要求:被代理类不能是最终类。不能被final修饰
* 提供者:第三方CGLIB
* 涉及的类:Enhancer
* 创建代理对象的方法:creat(Class,Callback);
* 参数的含义:
* Class:被代理对象的字节码
* Callback:如何代理。他和InvocationHandler的作用是一样的他也是一个接口,我们一般使用该接口的子接口MethodInterceptor
* 在使用时我们也是创建该接口的匿名内部类。
*/
Actor cglibAct = (Actor) Enhancer.create(actor.getClass(), new MethodInterceptor() {
/**
* 执行被代理对象的任何方法,都会经过该方法。他和基于接口动态代理的invoke方法方法的作用是一模一样的。
* 方法参数:
* 前面三个和invoke方法的参数含义都一样。
* MethodProxy methodProxy:当前执行方法的代理对象。一般不用。
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object rtValue = null;
//1.取出执行方法中的参数
Float money = (Float) args[0];
//2.判断当前执行的是什么方法
if ("basicAct".equals(method.getName())) {
//基本演出
if (money > 10000) {
//执行方法(开始表演)
rtValue = method.invoke(actor, money / 2);
}
}
if ("dangerAct".equals(method.getName())) {
//危险演出
if (money > 50000) {
//执行方法
rtValue = method.invoke(actor, money / 2);
}
}
return rtValue;
}
});
cglibAct.basicAct(20000);
cglibAct.dangerAct(60000);
}
}
**关于代理的选择 : ** 在spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式
**AOP相关术语 : **
JoinPoint(连接点):所谓连接点就是指那些被拦截到的点。在spring中,这些点指的就是方法,因为spring只支持方法类型的连接点。
Pointcut(切入点):所谓切入点就是指我们要对那些JoinPoint进行拦截的定义。(被增强的就是切入点)
Advice(通知/增强):所谓通知是指拦截到JoinPoint之后所要做的事情就是通知。通知类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期间为类动态地添加一些方法或field。
Target(目标对象):代理目标对象。
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而aspectJ采用编译期织入和类装载期织入。
Proxy(代理):一个类AOP织入增强后,就产生一个结果代理类
Aspect(切面):是切入点和通知(引介)的结合。
导入坐标 —> 配置好IoC —> 按照四步骤进行配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="customerService" class="com.itheima.service.impl.CustomerServiceImpl">bean>
<bean id="logger" class="com.itheima.utils.Logger">bean>
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))">aop:pointcut>
<aop:aspect id="logAdvice" ref="logger">
<aop:before method="printLog" pointcut-ref="pt1">aop:before>
aop:aspect>
aop:config>
beans>