您现在的位置是:首页 >技术教程 >Spring Aop网站首页技术教程
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接口获得工厂,进而获得代理对象。





QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
U8W/U8W-Mini使用与常见问题解决
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结