AOP简述

什么是AOP

AOP是面向切面编程,是一种编程思想。

为什么要有AOP

目的是用于实现关注点代码和业务代码的分离解耦,从而提高关注点代码的可维护性和可扩展性

AOP专业术语:

aspect:切面
advice:通知 - 切面类中的方法
joinPoint:连接点 - 业务类里面所有的方法(预备役)
pointCut: 切点 - 关注点代码切入的连接点叫做切点
weaving:织入 - 关注点代码织入业务代码

AOP通知类型:

前置通知:  @Before
后置通知:  @After
环绕通知:  @Around
返回后通知:  @AfterReturing
抛出异常后通知:  @AfterThrowing

AOP底层原理- 动态代理机制

运行期通过代理机制将关注点代码植入到业务代码中,产生的新对象叫做代理对象,运行期执行的是代理对象中融合之后的方法代码

AOP简述_第1张图片

 动态代理机制分类:

JDK动态代理:为实现类接口的目标对象生成代理对象
CGLIB动态代理:为没有实现接口的目标对象生成代理对象

JDK动态代理

适用于实现了接口的目标对象,为其生成代理对象,底层代码示例
生成代理对象需要什么分析:
------1. 创建一个实现了接口的目标对象
package ;

public interface UserOperation {
    void login(String userName,String pwd);
}
------//实现接口
package ;

public class UserOperationImpl implements UserOperation {
    @Override
    public void login(String userName, String pwd) {
        System.out.println("开始登陆!");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("登陆成功!");
    }
}

------2. 创建切面类对象,保存增强/关注点代码
    	- 实现InvocationHandler接口
package ;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

public class TimeAspect implements InvocationHandler {
    private Object target;//目标对象 这里面包含我要拦截的方法
    public TimeAspect(Object target){
        this.target = target;
    }
    //重写方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long t1 = System.currentTimeMillis();//当前时间的毫秒
        Object returnVal = method.invoke(target,args);//参数 目标对象里面的方法
        long t2 = System.currentTimeMillis();//当前事件
        System.out.println("耗时:"+(t2-t1)+"ms");
        return returnVal;//原来方法返回什么 代理对象返回什么
    }
}

-----3. 使用JDK的动态代理机制生成代理对象
package ;

import java.lang.reflect.Proxy;

public class JDKProxyFctory {
    public static void main(String[] args) {
        //创建目标对象
        UserOperation userOperation = new UserOperationImpl();
        //创建增强对象
        TimeAspect aspect = new TimeAspect(userOperation);
        //使用JDK的api来生成代理对象 返回代理对象Object类型
        UserOperation proxy = (UserOperation) Proxy.newProxyInstance(
                userOperation.getClass().getClassLoader(),//目标对象的类加载器
                userOperation.getClass().getInterfaces(),//目标对象所属类的所有接口类型
                aspect);//增强对象
        //调用代理对象中的login方法
        proxy.login("tom","123");
        System.out.println(proxy.getClass());
    }
}

-----4. 调用代理对象中的方法,看执行结果是否为融合后的代码

出现$Proxy0就代表成功了

 AOP简述_第2张图片

CGLib动态代理

适用于没有实现接口的目标对象,为其生成代理对象 底层代码示例
-----1. 创建一个没有实现接口的目标对象
package ;

public class UserRegist {
    public void regist(){
        System.out.println("开始注册!");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("注册成功!");
    }
}

-----2. 创建增强类对象
    	-实现MethodInterceptor
package ;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
//方法拦截接口
public class CglibTimeAspect  implements MethodInterceptor {
    private Object target;//跟上文JDK同理
    public CglibTimeAspect(Object target){
        this.target = target;
    }


    @Override                //代理对象,拦截到的方法,拦截的方法的参数列表,方法代理对象
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        long t1 = System.currentTimeMillis();
        Object returnVal = method.invoke(target,args);
        long t2 = System.currentTimeMillis();
        System.out.println("耗时:"+(t2-t1)+"ms");
        return returnVal;
    }
}

-----3. 使用CGLIB的api方法生成代理对象
import org.springframework.cglib.proxy.Enhancer;

public class CglibProxyFactory {
    public static void main(String[] args) {
        //创建目标对象
        UserRegist userRegist = new UserRegist();
        //创建增强对象
        CglibTimeAspect aspect = new CglibTimeAspect(userRegist);
        //使用cglib的api方法生成代理对象
        UserRegist proxy = (UserRegist) Enhancer.create(userRegist.getClass(),aspect);
        //通过代理对象调用目标方法
        proxy.regist();
        System.out.println(proxy.getClass());
    }
}

-----4. 调用代理对象中的目标方法,看执行的结果是否为组合后的代码

出现下图就代表成功了 

AOP简述_第3张图片

 Spring中AOP代理机制的选择

spring的aop会自动根据目标对象是否实现类接口来智能的选择动态代理机制.
    若目标对象实现了接口,则选择JDK动态代理机制
    若目标对象没有实现接口,则自动选择CGLIB动态代理机制
    
从SpringBoot2.xx版本开始,不论目标对象是否实现了接口,均会默认选择CGLIB动态代理机制.

AOP应用

1. spring的声明式事务管理
2. 记录日志
3. 性能统计

你可能感兴趣的:(java)