AOP详解与实例第一章
程序员文章站
2024-03-25 21:14:16
...
AOP介绍
AOP面向切面编程,主要解决特定问题,如:代码重复问题、关注点分离(
水平分离:展示层 ->服务层->持久层
垂直分离:模块划分 订单、库存等模块
切面分离:分离功能性与非功能性需求)
AOP优点
- 集中处理某一个关键点/横切逻辑
- 可以很方便地添加/删除关注点
- 侵入性少,增加代码可读性及可维护性
AOP使用场景
- 权限控制
- 缓存控制
- 事物控制
- 日志控制
- 性能监控
- 分布式追踪
- 异常处理
小试牛刀
需求背景产品添加或删除操作只有管理员才可以进行,下面我们就普通实现 VS AOP实现。
新建一个项目
https://start.spring.io/
配置如图
pom.xml添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
代码实现结构如下
实体类
package com.demo.aop.entity;
public class Product {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
方便切换用户
package com.demo.aop.security;
/**
* 方便切换用户
*/
public class CurrentUserHolder {
private static final ThreadLocal<String> holder = new ThreadLocal<>();
public static String get() {
return holder.get() == null ? "unKnown":holder.get();
}
public static void set(String user){
holder.set(user);
}
}
权限类,设置你的权限
package com.demo.aop.sevice;
import com.demo.aop.security.CurrentUserHolder;
import org.springframework.stereotype.Component;
@Component
public class AuthService {
//检查权限
public void checkAccess(){
String user = CurrentUserHolder.get();
if(!"admin".equals(user)){
throw new RuntimeException("操作不允许!");
}
}
}
AOP 注解方式
package com.demo.aop.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AdiminOnly {
}
//------------------------分割线--------------------------------------
package com.demo.aop.security;
import com.demo.aop.sevice.AuthService;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SecurityAspect {
@Autowired
AuthService authService;
@Pointcut(value = "@annotation(com.demo.aop.annotation.AdiminOnly)")
public void adminOnly(){}
@Before("adminOnly()")
public void check(){
authService.checkAccess();
}
}
package com.demo.aop.sevice;
import com.demo.aop.annotation.AdiminOnly;
import com.demo.aop.entity.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 模拟现实场景业务调用
*/
@Service
public class ProductService {
//传统方法
@Autowired
AuthService authService;
//模拟新增操作 传统方法
public void insert(Product product){
authService.checkAccess();
System.out.println("新增操作成功!");
}
//删除造成 AOP 注解方法 只需注解即可
@AdiminOnly
public void delete(String id){
System.out.println("删除操作成功!");
}
}
演示
package com.demo.aop.sevice;
import com.demo.aop.entity.Product;
import com.demo.aop.security.CurrentUserHolder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ProductServiceTest{
@Autowired
ProductService productService;
//传统方式
@Test
public void insert() {
CurrentUserHolder.set("tom");
productService.insert(new Product());
}
//切面方式
@Test
public void delete() {
CurrentUserHolder.set("admin");
productService.delete("1");
}
}
运行:
运行传统方法insert,出现错误,如果想要正确把tom 改为 admin 测试即可
运行AOP注解方式如下,如果想要错误把admin改为tom即可
是不是初步了解了呢,下面我讲下语法使用等介绍,请看 “AOP详解与实例第二章” 。