SpringAOP原理

1. 代理模式(Proxy Pattern)

其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。

代理分为两种方式: 静态代理与动态代理

静态代理是在程序运行之前就确立了代理关系; 而动态代理则是运行时才确立代理关系.

举个例子: 对于普通人来说, 有官司来了才会去找律师; 而对于企业来说, 企业内会有一个法律顾问, 官司来了法律顾问上. 前者相当于动态代理, 后者就相当于静态代理.

1.1 静态代理

先来看看关系图:
在这里插入图片描述
业务接口ISomeService中的方法是: 需要被增强的方法

目标类SomeServiceImpl是: 代理类要增强的类,实现ISomeService接口

代理类SomeServiceProxy实现了ISomeService接口,主要有两个任务:

  • 调用目标类的目标方法
  • 增强目标方法

下面看代码:
步骤 1
创建一个接口

package Proxy_Pattern;

public interface ISomeService {
    public void doService1();
    public void doService2();

}

步骤 2
创建实现接口的实体类

  1. 目标类
package Proxy_Pattern;

public class SomeServiceImpl implements ISomeService {
    @Override
    public void doService1() {
        System.out.println("This is service 1");
    }

    @Override
    public void doService2() {
        System.out.println("This is service 2");
    }
}
  1. 代理类
package Proxy_Pattern;

public class SomeServiceProxy implements ISomeService {
    ISomeService target;
    
	//传入目标类
    public SomeServiceProxy(ISomeService target){
        this.target = target;
    }

    @Override
    public void doService1() {
    	//增强方法
        System.out.println("hello everyone");
        //目标类的方法
        target.doService1();
    }

    @Override
    public void doService2() {
    	//增强方法
        System.out.println("good morning");
        //目标类的方法
        target.doService2();
    }
}

步骤 3
当被请求时,使用 SomeServiceProxy来获取 SomeServiceImpl 类的对象。

package Proxy_Pattern;

public class Test {
    public static void main(String[] args) {
        ISomeService target = new SomeServiceImpl();
        ISomeService proxy = new SomeServiceProxy(target);
        proxy.doService1();
        System.out.println("================");
        proxy.doService2();
    }
}

步骤 4
执行程序,输出结果:

hello everyone
This is service 1
================
good morning
This is service 2

1.2 动态代理

动态代理又分为两种,一中是JDK动态代理, 一种是CGLIB动态代理

1.2.1 JDK动态代理

JDK动态代理要求, 目标类与代理类要实现同一接口
无需创建代理类, 可以通过Proxy包下的newProxyInstance方法返回一个代理类的实例(动态代理对象)
在这里插入图片描述
先来看关系图:
在这里插入图片描述
步骤1
创建一个接口

package JDKDynamicProxy;

public interface ISomeService {
    public void doService1();
    public void doService2();
}

步骤2
创建接口的实现类

package JDKDynamicProxy;

public class SomeServiceImpl implements ISomeService {
    @Override
    public void doService1() {
        System.out.println("This is service1");
    }

    @Override
    public void doService2() {
        System.out.println("This is service2");
    }
}

步骤3
创建调用处理器

package JDKDynamicProxy;

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

public class ServiceHandler implements InvocationHandler {
    Object target;
    //传入目标类对象
    public ServiceHandler(Object target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    	//增强逻辑,如果不进行判断,会增强所有的方法
        System.out.println("执行" + method.getName() +"方法");
        //调用目标方法
        method.invoke(target, args);
        return null;
    }
}

在这里插入图片描述
步骤 4
当被请求时,使用 Proxy.newInstance()返回一个代理类实例,来获取 SomeServiceImpl 类的对象。

package JDKDynamicProxy;

import Proxy_Pattern.ISomeService;
import Proxy_Pattern.SomeServiceImpl;
import java.lang.reflect.Proxy;

public class Test {

    public static void main(String[] args) {
    	//目标类
        ISomeService target = new SomeServiceImpl();
        //方法处理器
        ServiceHandler handler = new ServiceHandler(target);
        //返回一个代理类实例
        ISomeService proxy = (ISomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), handler);
                
        proxy.doService1();
        System.out.println("==================");
        proxy.doService2();

    }
}

其中newProxyInstance方法:

		newProxyInstance(ClassLoader loader,//一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
                         Class<?>[] interfaces,//一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口
                         InvocationHandler h//一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
                         )

步骤 5
执行程序,输出结果:

执行doService1方法
This is service 1
==================
执行doService2方法
This is service 2

1.2.2 CGLIB动态代理

CGLIB动态代理, 目标类没有生成接口, 要生成代理对象.
原理:通过子类进行增强(子类增强父类)
在这里插入图片描述
在这里插入图片描述
先来看关系图:
在这里插入图片描述
步骤1
创建目标类

package CglibProxy;


public class SomeService{

    public void doService1() {
        System.out.println("This is service1");
    }

    public void doService2() {
        System.out.println("This is service2");
    }
}

步骤2
创建调用处理器

package CglibProxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class Proxy implements MethodInterceptor {
    Object target;

    public Proxy(Object target){
        this.target = target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    	//增强逻辑
        System.out.println("执行" + method.getName() +"方法");
        //目标对象方法的调用
        method.invoke(target, objects);
        return null;
    }

    public static Object getProxy(Object target){
        Enhancer enhancer = new Enhancer();
        // 设置需要代理的对象, 设置为父类
        enhancer.setSuperclass(target.getClass());
        // 设置代理人
        enhancer.setCallback(new Proxy(target));
        // 返回代理类的实例
        return enhancer.create();
    }
}

当代理对象的方法被调用时,就会执行intercept方法,
在这里插入图片描述
步骤3
当被请求时,使用 getProxy()方法来获得代理类实例,利用代理对象获取 SomeService类的对象。

package CglibProxy;

public class Test {
    public static void main(String[] args) {
        SomeService target = new SomeService();
        SomeService proxy = (SomeService) Proxy.getProxy(target);
        proxy.doService1();
        System.out.println("=============");
        proxy.doService2();
    }
}

步骤4
输入结果

执行doService1方法
This is service1
=============
执行doService2方法
This is service2

1.2.3 两种动态代理的区别

JDK动态代理只能对实现了接口的类生成代理,而不能针对类

CGLIB是针对类实现代理(对接口也可以实现),主要是对指定的类生成一个子类,覆盖其中的方法(继承)

2. SpringAOP

AOP思想的实现一般都是基于 代理模式 ,在JAVA中一般采用JDK动态代理模式,但是我们都知道,JDK动态代理模式只能代理接口而不能代理类。因此,Spring AOP 会这样子来进行切换,因为Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理。

  • 如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
  • 如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类——不过这个选择过程对开发者完全透明、开发者也无需关心。
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP(Aspect-Oriented Programming)是一种基于面向切面编程的技术,它通过将一个应用程序分解成许多独立的部分,从而提高了应用程序的模块化程度,同时也提高了代码的可重用性和可维护性。 Spring AOP 是在运行时对程序进行修改的,它不需要重新编译源代码,因此使得代码的维护和修改更加方便。Spring AOP 原理主要分为以下几个方面: 1. 切面(Aspect):切面是一个类,其中包含了一组相关的Advice和其他相关的代码,用于在目标对象的方法执行前、执行后或者抛出异常时执行相应的操作。 2. 连接点(Join point):连接点是指在应用程序的执行过程中,可以被切面拦截的点,比如方法调用、异常抛出、属性赋值等。 3. 通知(Advice):通知是指在连接点处执行的代码,有多种类型的通知,包括前置通知(Before advice)、后置通知(After advice)、返回通知(After returning advice)、异常通知(After throwing advice)和环绕通知(Around advice)。 4. 切入点(Pointcut):切入点是一个表达式,用于定义哪些连接点会被切面拦截。 5. 代理(Proxy):代理是指在目标对象和切面之间创建的对象,它可以拦截目标对象的方法调用,并在方法执行前后执行相应的通知。 Spring AOP 的实现机制主要是通过 JDK 动态代理或者 CGLIB 动态代理来实现的。当目标对象实现了接口时,Spring AOP 使用 JDK 动态代理,否则使用 CGLIB 动态代理。在 JDK 动态代理中,代理对象实现了与目标对象相同的接口,而在 CGLIB 动态代理中,代理对象是目标对象的子类。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值