增加spel配合注解示例

This commit is contained in:
wyl
2022-05-08 22:17:42 +08:00
parent fa85a8b282
commit 7735590c7c
22 changed files with 573 additions and 20 deletions
+74
View File
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wyl</groupId>
<artifactId>spring-boot-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-common</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,22 @@
package com.wyl.spring.boot.common;
import com.wyl.spring.boot.common.bean.init.BeanInitExample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
public class SpringBootCommonApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootCommonApplication.class, args);
}
@Bean
BeanInitExample beanInitExample() {
return new BeanInitExample();
}
}
@@ -0,0 +1,18 @@
package com.wyl.spring.boot.common.aop.advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor;
/**
* DATE 4:45 PM
*
* @author mzt.
*/
public class LogAdvisor extends AbstractBeanFactoryPointcutAdvisor {
LogPointcut logPointcut = new LogPointcut();
@Override
public Pointcut getPointcut() {
return logPointcut;
}
}
@@ -0,0 +1,25 @@
package com.wyl.spring.boot.common.aop.advisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LogAutoConfigure {
@Bean
LogPointcut logPointcut() {
return new LogPointcut();
}
@Bean
LogAdvisor logAdvisor() {
LogAdvisor logAdvisor = new LogAdvisor();
logAdvisor.setAdvice(logInterceptor());
return logAdvisor;
}
@Bean
LogInterceptor logInterceptor() {
return new LogInterceptor();
}
}
@@ -0,0 +1,23 @@
package com.wyl.spring.boot.common.aop.advisor;
import com.wyl.spring.boot.common.spel.service.Evaluator;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* @author: wangyl
* @date: 2022/5/1
* @description: 再方法执行前以及执行进行代理操作
*/
public class LogInterceptor implements MethodInterceptor {
private final Evaluator evaluator = new Evaluator();
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Advisor 方法执行前");
Object proceed = invocation.proceed();
System.out.println("Advisor 方法执行后");
return proceed;
}
}
@@ -0,0 +1,21 @@
package com.wyl.spring.boot.common.aop.advisor;
import com.wyl.spring.boot.common.aop.annotation.LogTest;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* @author: wangyl
* @date: 2022/4/30
* @description: apo静态切入点,切入所有matches返回true的方法
*/
public class LogPointcut extends StaticMethodMatcherPointcut implements Serializable {
@Override
public boolean matches(Method method, Class<?> targetClass) {
LogTest annotation = method.getAnnotation(LogTest.class);
return !Objects.isNull(annotation);
}
}
@@ -0,0 +1,10 @@
package com.wyl.spring.boot.common.aop.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited//注解会被继承
@Documented
public @interface LogTest {
}
@@ -0,0 +1,65 @@
package com.wyl.spring.boot.common.aop.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 接口出入参数信息依赖swagger
*
* @author wangyl
* @version V1.0
* @ClassName: WebLogAspect
* @Date: 2022/1/5 22:58
*/
@Aspect
@Slf4j
@Component
public class LogAspect {
/**
* 以自定义 @WebLog 注解为切点
*/
@Pointcut("@annotation(com.wyl.spring.boot.common.aop.annotation.LogTest)")
public void webLog() {
}
/**
* 在切点之前织入
*
* @param joinPoint
* @throws Throwable
*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) {
System.out.println("Aspect Before 打印");
}
/**
* 在切点之后织入
*
* @throws Throwable
*/
@After("webLog()")
public void doAfter() {
System.out.println("Aspect After 打印");
}
/**
* 环绕
*
* @param proceedingJoinPoint
* @return
* @throws Throwable
*/
@Around("webLog()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Aspect 方法执行前打印 打印");
Object proceed = proceedingJoinPoint.proceed();
System.out.println("Aspect 方法执行后打印 打印");
return proceed;
}
}
@@ -0,0 +1,33 @@
package com.wyl.spring.boot.common.bean.init;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class BeanInitExample implements InitializingBean, DisposableBean {
public BeanInitExample() {
System.out.println("构造函数被调用");
}
@PostConstruct
public void init() {
System.out.println("PostConstruct 被调用");
}
@PreDestroy
public void disposable() {
System.out.println("PreDestroy 被调用");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean 被调用");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean 被调用");
}
}
@@ -0,0 +1,13 @@
package com.wyl.spring.boot.common.service;
import com.wyl.spring.boot.common.spel.bean.Order;
import java.util.List;
public interface LogTestService {
void test();
void testSPEL(Order order);
void testSPELList(List<Order> orders);
}
@@ -0,0 +1,30 @@
package com.wyl.spring.boot.common.service.impl;
import com.wyl.spring.boot.common.aop.annotation.LogTest;
import com.wyl.spring.boot.common.service.LogTestService;
import com.wyl.spring.boot.common.spel.annotation.SpelTest;
import com.wyl.spring.boot.common.spel.bean.Order;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class LogTestServiceImpl implements LogTestService {
@Override
@LogTest
public void test() {
System.out.println("testLog");
}
@SpelTest(spel = "{#order.id}")
public void testSPEL(Order order) {
System.out.println(123);
}
@Override
@SpelTest(spel = "{#orders.![#this.id]}")
public void testSPELList(List<Order> orders) {
System.out.println();
}
}
@@ -0,0 +1,61 @@
package com.wyl.spring.boot.common.spel;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wyl.spring.boot.common.spel.annotation.SpelTest;
import com.wyl.spring.boot.common.spel.service.EvaluationContext;
import com.wyl.spring.boot.common.spel.service.Evaluator;
import com.wyl.spring.boot.common.spel.service.RootObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Slf4j
@Component
public class SpelTestAspect {
/**
* 日志SpEL解析器
*/
private final Evaluator evaluator = new Evaluator();
/**
* 日志切入点
*/
@Pointcut(value = "@annotation(com.wyl.spring.boot.common.spel.annotation.SpelTest)")
public void SpelTestPointCut() {
}
@Around(value = "SpelTestPointCut()")
public Object errorLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
proceedingJoinPoint.getArgs();
Signature signature = proceedingJoinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
Object[] args = proceedingJoinPoint.getArgs();
Class targetClass = AopProxyUtils.ultimateTargetClass(proceedingJoinPoint.getTarget());
SpelTest annotation = method.getAnnotation(SpelTest.class);
/**
* 生成元数据
*/
RootObject rootObject = new RootObject();
/**
* 生成spel上下文
*/
EvaluationContext context = new EvaluationContext(rootObject, method, args, evaluator.getDiscoverer());
/**
* 解析spel
*/
Object content = evaluator.parse(annotation.spel(), context);
System.out.println(content);
return proceedingJoinPoint.proceed();
}
}
@@ -0,0 +1,15 @@
package com.wyl.spring.boot.common.spel.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SpelTest {
/**
* spel
*/
String spel();
}
@@ -0,0 +1,9 @@
package com.wyl.spring.boot.common.spel.bean;
import lombok.Data;
@Data
public class Order {
Integer id;
String name;
}
@@ -0,0 +1,22 @@
package com.wyl.spring.boot.common.spel.service;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.ParameterNameDiscoverer;
import java.lang.reflect.Method;
/**
* @author: wangyl
* @date: 2022/5/8
* @description: 解析上下文, 用于整个解析环境
*/
public class EvaluationContext extends MethodBasedEvaluationContext {
/**
* 构造方法
*
* @param rootObject 数据来源对象
* @param discoverer 参数解析器
*/
public EvaluationContext(RootObject rootObject, Method method, Object[] arguments, ParameterNameDiscoverer discoverer) {
super(rootObject, method, arguments, discoverer);
}
}
@@ -0,0 +1,52 @@
package com.wyl.spring.boot.common.spel.service;
import lombok.Getter;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
/**
* @author: wangyl
* @date: 2022/5/8
* @description: spel解析处理器
*/
@Getter
public class Evaluator {
/**
* SpEL解析器
*/
private final SpelExpressionParser parser = new SpelExpressionParser();
/**
* 参数解析器
*/
private final ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
/**
* 表达式模板
*/
private final ParserContext template = new TemplateParserContext("{", "}");
/**
* 解析
*
* @param expression 表达式
* @param context 日志表达式上下文
* @return 表达式结果
*/
public Object parse(String expression, EvaluationContext context) {
return getExpression(expression).getValue(context);
}
/**
* 获取翻译后表达式
*
* @param expression 字符串表达式
* @return 翻译后表达式
*/
private Expression getExpression(String expression) {
return getParser().parseExpression(expression, template);
}
}
@@ -0,0 +1,15 @@
package com.wyl.spring.boot.common.spel.service;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author: wangyl
* @date: 2022/5/8
* @description: spel解析得元数据
*/
@Getter
@AllArgsConstructor
public class RootObject {
}
@@ -0,0 +1,51 @@
package com.wyl.spring.boot.common;
import com.wyl.spring.boot.common.service.LogTestService;
import com.wyl.spring.boot.common.spel.bean.Order;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.List;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
class SpringBootCommonApplicationTests {
@Autowired
LogTestService logTestService;
@Test
void beanInit() {
}
@Test
void LogTestServiceTest() {
logTestService.test();
}
@Test
void SpelTest() {
Order order = new Order();
order.setId(123);
order.setName("wyl");
logTestService.testSPEL(order);
}
@Test
void SpelListTest() {
Order order1 = new Order();
order1.setId(1);
order1.setName("wyl1");
Order order2 = new Order();
order2.setId(2);
order2.setName("wyl2");
Order order3 = new Order();
order3.setId(3);
order3.setName("wyl3");
List<Order> orders = Arrays.asList(order1, order2, order3);
logTestService.testSPELList(orders);
}
}
@@ -1,20 +0,0 @@
package com.wyl.example;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}
@@ -0,0 +1,5 @@
package com.wyl.example.service;
public interface Service {
void test();
}
@@ -0,0 +1,8 @@
package com.wyl.example.service;
public class ServiceTest implements Service{
@Override
public void test() {
}
}