您现在的位置是:首页 >技术教程 >Spring Aop网站首页技术教程

Spring Aop

_yangshen 2026-03-24 00:01:04
简介Spring Aop

代理设计模式

为什么需要代理设计模式?

代理设计模式:通过代理类,为原始类(目标类)添加额外功能

好处:利于目标类或者原始类的代码维护

目标类(原始类)指的是业务类---->核心功能

目标方法,原始方法:目标类中或者原始类中的方法

额外功能:附加功能 例如:日志 事务 性能

代理开发的核心要素:

代理类=目标类(原始类) + 额外功能 + (原始类)实现相同的接口

静态代理设计模式

静态代理:为每一个原始类,手动编写一个代理类Proxy.class

现实生活中的例子

package com.baizhi.proxy;

public class User {
    private String name;
    private String password;

    public User() {}

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }



    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    @Override
    public String toString() {
        return "User{" +
                "name='" + name + ''' +
                ", password='" + password + ''' +
                '}';
    }
}
package com.baizhi.proxy;

public interface UserService {


    void register(User user);

    boolean login(String name, String password);

}

package com.baizhi.proxy;

public class UserServiceImpl implements UserService {
    @Override
    public void register(User user) {
        System.out.println("UserServiceImpl.register");
    }

    @Override
    public boolean login(String name, String password) {
        System.out.println("UserServiceImpl.login");
        return false;
    }
}
package com.baizhi.proxy;

public class UserServiceProxy implements UserService{
    private UserService userService = new UserServiceImpl();
    @Override
    public void register(User user) {
        System.out.println("-----------log-----------");
        userService.register(user);
    }

    @Override
    public boolean login(String name, String password) {
        System.out.println("--------log---------");
        return userService.login(name,password);
    }
}

静态代理设计问题:

1.静态类的数量过多,不利于管理 例如:UserServiceImpl UserServiceProxy

OrderServiceImpl OrderServiceProxy…

2.额外功能维护性差,不利于代码的维护…

动态代理设计模式

动态代理:通过代理类,为原始类(目标类)添加额外功能

好处:利于目标类或者原始类的代码维护

环境搭建:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.1.12.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.8</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.3</version>
</dependency>

1.创建原始类对象

package com.baizhi.proxy;

public class UserServiceImpl implements UserService {
    @Override
    public void register(User user) {
        System.out.println("UserServiceImpl.register");
    }

    @Override
    public boolean login(String name, String password) {
        System.out.println("UserServiceImpl.login");
        return false;
    }
}

2.提供额外功能 实现MethodBeforeAdvice接口

package com.baizhi.proxy;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class Before implements MethodBeforeAdvice {
   /**
     * 需要把运行在原始方法之前运行的额外功能,书写在before方法中
     * @param method 额外功能所增加的那个原始方法 login(String name, String password) register(User user)
     * @param objects 额外功能所增加的那个原始方法的参数
     * @param o 原始对象
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("Before.before");
    }
}

3.定义切入点 也就是额外功能加入的位置 由程序员决定额外功能加入哪个原始方法

4.组装

<bean id="userService" class="com.baizhi.proxy.UserServiceImpl"></bean>
<bean id="before" class="com.baizhi.proxy.Before"></bean>
<aop:config>
<!--        所有的方法 都作为切入点 加入额外功能-->
    <aop:pointcut id="pc" expression="execution(* *(..))"/>
<!--        组装:目的把切入点 与 额外功能进行整合-->
    <aop:advisor advice-ref="before" pointcut-ref="pc"/>
</aop:config>

5.调用

细节分析:

1.spring创建的动态代理类在哪里?

spring框架在运行时,通过动态字节码技术,在jvm创建时,运行jvm内部,等程序结束后,会和jvm一起消失。

动态字节码技术:通过第三方动态字节码框架,在jvm中创建对应类的字节码,进而创建对象,当jvm运行结束的时候,动态字节码跟着消失。

好处:不需要定义类文件,都是在jvm运行的过程中动态进行创建的,所以不会造成静态代理类文件数量过多的情况,影响项目的管理。

2.动态代理编程会简化代理的开发

3.维护性大大增强

MethodInterceptor(方法拦截器)前后 前 后 抛出异常都能

切入点详解

切入点决定了额外功能加入的位置

<aop:config>
<!--        所有的方法 都作为切入点 加入额外功能-->
    <aop:pointcut id="pc" expression="execution(* *(..))"/>
<!--        组装:目的把切入点 与 额外功能进行整合-->
    <aop:advisor advice-ref="before" pointcut-ref="pc"/>
</aop:config>

方法切入点表达式

* *(..) 代表着所有的方法
* -----> 修饰符 返回值
* -----> 方法名
()-----> 参数表
..对于参数没有任何要求(参数有没有 有几个 参数什么类型都可以)

// 定义login方法
* login(..)
// 定义register方法
* register(..)
//定义login 方法 且参数是两个字符串
* login(String,String) 如果不是java.lang包下的数据类型 那么必须要写全限定名 * register(com.baizhi.basic.User)
* login(String,..) 代表着前面一个参数为String 后面的参数有没有无所谓
// 精准表达 修饰符返回值 包 类 方法 (方法参数)

修饰符 返回值          包..方法(参数)
*                     com.baizhi.proxy.UserServiceImpl.login(..)

类切入点

指定特定的类作为切入点添加额外功能

忽略包

1.包只存在一级

    • **.**UserServiceImpl.*(…)

2.包有多级包

  • **…**UserServiceImpl.(…)

包切入点(应用最为广泛)

    • com.baizhi.proxy..(…)当前包
    • com.baizhi.proxy….(…)当前包及其子包

切入点函数

用于执行切入点函数

1.execution

最为重要的切入点函数,功能最全

执行 方法切入点表达式 类切入点表达式 包切入点表达式

但是书写麻烦

2.args

作用:主要用于函数(方法)参数的匹配

切入点:方法参数必须是得两个字符串类型的参数

execution(* *(String,String))

args(String,String)

3.within

作用:主要用于进行类 包切入点表达式的匹配

切入点:UserServiceImpl 这个类

4.@ annotation

切入点函数的逻辑运算

整合多个切入点函数一起配合工作 完成复杂的需求

1.and操作

2.or操作

AOP(Aspect Oriented Programing)

概念:面向切面编程 spring动态代理开发,通过代理类为原始类添加额外功能。好处:利于原始类的维护

AOP:面向切面编程=spring动态代理开发 以切面为基本单位的程序开发,通过切面间的彼此协同,相互调用,完成程序的构建 切面 = 切入点 + 额外功能

OOP: 面向对象编程 java以对象为基本单位的程序开发 通过对象间的彼此协同,相互调用,完成程序的构建。

POP:面向过程开发(函数 方法)例如c语言。

以过程为基本单位的程序开发,通过程序见的彼此协同,相互调用,完成程序的构建。

AOP开发步骤

1.提供原始对象

2.添加额外功能

3.定义切入点

4组合切面

切面的名词解释

切面 = 切入点 + 额外功能

AOP底层实现原理

动态代理

JDK动态代理

public class TestProxy {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        Object object = Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserService.class.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("TestProxy.invoke");
                Object ret = method.invoke(userService,args);
                return ret;
            }
        });
        System.out.println(object);
    }
}

CGLIb动态代理

采用的是继承关系去实现动态代理的

基于注解的aop编程开发步骤

1.原始对象

package com.baizhi.aspect;

import com.baizhi.proxy.User;

public interface UserService {


    void register(User user);

    boolean login(String name, String password);

}

public class UserServiceImpl implements UserService {
    @Override
    public void register(User user) {
        System.out.println("UserServiceImpl.register");
    }

    @Override
    public boolean login(String name, String password) {
        System.out.println("UserServiceImpl.login");
        return false;
    }
}

2.额外功能

3.切入点

package com.baizhi.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MyAspect {

    @Around("execution(* com.baizhi.aspect.UserServiceImpl.login(String,String))")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object ret = null;
        try {
            System.out.println("MyAspect.around");
            ret = joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return ret;
    }



}

4.组装切面

<bean id="userService" class="com.baizhi.aspect.UserServiceImpl"/>

<bean id="around" class="com.baizhi.aspect.MyAspect"></bean>

<!--    告诉spring工厂使用注解AOP-->
<aop:aspectj-autoproxy/>

pointcut注解

简化编程

@Aspect
public class MyAspect {


    @Pointcut("execution(* com.baizhi.aspect.UserServiceImpl.login(String,String))")
    public void myPointcut() {

    }

    @Around("myPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object ret = null;
        try {
            System.out.println("MyAspect.around");
            ret = joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return ret;
    }
}

AOP的坑

在同一个业务类中,进行业务方法间的相互调用,只有最外层的方法,才是加入了额外功能(内部的方法,通过普通的方式的调用,都调用的是原始的方法)。如果想让内层的方法也调用代理对象的方法,就要实现ApplicationContextAware接口获得工厂,进而获得代理对象。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。