In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article analyzes "what is the implementation of Aspect annotated by springboot". The content is detailed and easy to understand, and friends who are interested in "what is the implementation of springboot annotations Aspect" can follow the editor's train of thought to read it slowly and deeply. I hope it will be helpful to everyone after reading. Let's follow the editor to learn more about "what is the implementation of Aspect annotated by springboot".
target
A custom annotation is provided below to implement the DEMO of the business approval operation, without the configuration function of the approval process.
The specific plan is
Customize an Aspect annotation, intercept the sevice method, persist the intercepted information for approval; obtain persistent data during approval, and execute the target method.
Implement POM 4.0.0 org.springframework.boot spring-boot-starter-parent 2.5.8 com.proc process-test 1.0.0-SNAPSHOT process-test Demo project for Spring Boot 1.8 Org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test Org.springframework.boot spring-boot-starter-aop org.springframework.boot spring-boot-configuration-processor true Com.alibaba transmittable-thread-local 2.12.2 org.springframework.boot spring-boot-maven -plugin some entity classes CheckedParam
Used to wrap the parameters passed in the page
Package com.proc.model;import java.util.List;public class CheckedParam {/ / business tag, passed in by the page, is used to parse the data according to tagPageJs when the page is approved, and render it to the page. The examination and approval administrator can see the original data private List data; public String getTagPageJs () {return tagPageJs passed into the approved content private String tagPageJs; / / page. } public void setTagPageJs (String tagPageJs) {this.tagPageJs = tagPageJs;} public List getData () {return data;} public void setData (List data) {this.data = data;}} ProcessDbModel
Intercepted information wrapper class, used to persist data
Package com.proc.model;public class ProcessDbModel {/ / bean target class fully qualified name private String targetClassName; / intercepted service method name private String methodName; / / page passed in tagPageJs or Checked annotations tag private String tag; private String description; / / intercepted service input parameter type, including generic information private String paramTypes / / intercepted service input parameter value private String paramArgs; / intercepted service input parameter value or raw data passed in to the page private String data; public String getTargetClassName () {return targetClassName;} public void setTargetClassName (String targetClassName) {this.targetClassName = targetClassName } public String getMethodName () {return methodName;} public void setMethodName (String methodName) {this.methodName = methodName;} public String getTag () {return tag;} public String getDescription () {return description } public void setDescription (String description) {this.description = description;} public void setTag (String tag) {this.tag = tag;} public String getParamTypes () {return paramTypes;} public void setParamTypes (String paramTypes) {this.paramTypes = paramTypes } public String getParamArgs () {return paramArgs;} public void setParamArgs (String paramArgs) {this.paramArgs = paramArgs;} public String getData () {return data;} public void setData (String data) {this.data = data @ Override public String toString () {return "ProcessDbModel [targetClassName=" + targetClassName + ", methodName=" + methodName + ", tag=" + tag + ", description=" + description + ", paramTypes=" + paramTypes + ", paramArgs=" + paramArgs + ", data=" + data + "]" }} the input object for testing package com.proc.model;import java.math.BigDecimal;public class Score {private BigDecimal langue; private BigDecimal math; private BigDecimal english; public BigDecimal getLangue () {return langue;} public void setLangue (BigDecimal langue) {this.langue = langue } public BigDecimal getMath () {return math;} public void setMath (BigDecimal math) {this.math = math;} public BigDecimal getEnglish () {return english;} public void setEnglish (BigDecimal english) {this.english = english } @ Override public String toString () {return "Score [langue=" + langue + ", math=" + math + ", english=" + english + "]";}} package com.proc.model;import java.util.List;public class Person {private String name; private String age; private String sex; private String testName Private String salary; private String work; private List grades; public String getName () {return name;} public void setName (String name) {this.name = name;} public String getAge () {return age } public void setAge (String age) {this.age = age;} public String getSex () {return sex;} public void setSex (String sex) {this.sex = sex;} public String getSalary () {return salary } public void setSalary (String salary) {this.salary = salary;} public String getTestName () {return testName;} public void setTestName (String testName) {this.testName = testName;} public String getWork () {return work } public void setWork (String work) {this.work = work;} public List getGrades () {return grades;} public void setGrades (List grades) {this.grades = grades } @ Override public String toString () {return "Person [name=" + name + ", age=" + age + ", sex=" + sex + ", testName=" + testName + ", salary=" + salary + ", work=" + work + ", grades=" + grades + "]";}} some utility classes
JacksonCanonicalUtil
Package com.proc.util;import com.fasterxml.jackson.core.type.TypeReference;import com.fasterxml.jackson.databind.JavaType;import com.fasterxml.jackson.databind.json.JsonMapper;public class JacksonCanonicalUtil {private static final JsonMapper MAPPER = new JsonMapper (); private JacksonCanonicalUtil () {} public static String toCanonical (Class clazz) {return MAPPER.getTypeFactory () .constructType (clazz) .toCanonical () } public static String toCanonical (TypeReference tr) {return MAPPER.getTypeFactory () .constructType (tr) .toCanonical ();} / / get JavaType public static JavaType constructFromCanonical (String canonical) {return MAPPER.getTypeFactory () .constructFromCanonical (canonical);}} from persistent data when deserialization
StringZipUtil
Used to compress and decompress strings to reduce persistent data footprint
Package com.proc.util;import java.io.ByteArrayOutputStream;import java.io.OutputStream;import java.nio.charset.StandardCharsets;import java.util.Base64;import java.util.zip.DeflaterOutputStream;import java.util.zip.InflaterOutputStream Public class StringZipUtil {private StringZipUtil () {} public static String zipBase64 (String text) {try (ByteArrayOutputStream out = new ByteArrayOutputStream ()) {try (OutputStream os = new DeflaterOutputStream (out)) {os.write (text.getBytes (StandardCharsets.UTF_8));} return Base64.getEncoder () .encodeToString (out.toByteArray ()) } catch (Exception e) {throw new RuntimeException ("string compression error", e);}} public static String unzipBase64 (String text) {try (ByteArrayOutputStream out = new ByteArrayOutputStream ()) {try (OutputStream os = new InflaterOutputStream (out)) {os.write (Base64.getDecoder (). Decode (text)) } return new String (out.toByteArray (), StandardCharsets.UTF_8);} catch (Exception e) {throw new RuntimeException ("error decompressing string", e);} Base64Util
Some parameter values are persisted after being converted to Base64
Package com.proc.util;import java.nio.charset.StandardCharsets;import java.util.ArrayList;import java.util.Base64;import java.util.List;import java.util.stream.Collectors;import com.fasterxml.jackson.databind.json.JsonMapper;public class Base64Util {private Base64Util () {} private static final JsonMapper MAPPER = new JsonMapper (); public static String [] toStrings (Object [] objs) {List list = new ArrayList () Try {for (Object obj: objs) {list.add (MAPPER.writeValueAsString (obj));} catch (Exception e) {throw new RuntimeException ("serialization object error", e) } return list.toArray (new String [0]);} public static String encode (String [] strs) {List list = new ArrayList (); for (String str: strs) {list.add (Base64.getEncoder (). EncodeToString (str.getBytes (StandardCharsets.UTF_8) } String join = list.stream () .collect (Collectors.joining ("|")); return join;} public static String [] decode (String text) {String [] strs = text.split ("\ |",-1); List list = new ArrayList () For (String base64: strs) {list.add (new String (Base64.getDecoder (). Decode (base64), StandardCharsets.UTF_8));} return list.toArray (new String [0]);} public static String encodeZip (Object [] objs) {return encodeZip (toStrings (objs)) } public static String encodeZip (String [] strs) {List list = new ArrayList (); for (String str: strs) {list.add (StringZipUtil.zipBase64 (str));} String join = list.stream () .collect (Collectors.joining ("|")) Return StringZipUtil.zipBase64 (join);} public static String [] decodeZip (String text) {String str = StringZipUtil.unzipBase64 (text); String [] strs = str.split ("\ |",-1); List list = new ArrayList () For (String base64: strs) {list.add (StringZipUtil.unzipBase64 (base64));} return list.toArray (new String [0]);}} SpringBootBeanUtilpackage com.proc.util;import java.util.Map;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component @ Componentpublic class SpringBootBeanUtil implements ApplicationContextAware {private static ApplicationContext applicationContext; @ Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException {SpringBootBeanUtil.applicationContext = applicationContext;} public static ApplicationContext getApplicationContext () {return applicationContext;} public static Object getBean (String name) {return applicationContext.getBean (name) } public static T getBean (Class clazz) {return (T) applicationContext.getBean (clazz);} public static T getBean (String name, Class clazz) {return applicationContext.getBean (name, clazz);} public static Map getBeansOfType (Class clazz) {return applicationContext.getBeansOfType (clazz) }} ProcessBeanUtil
Used to execute the target method
Package com.proc.util;import java.lang.reflect.Method;import org.springframework.util.ReflectionUtils;public class ProcessBeanUtil {private ProcessBeanUtil () {} public static Object excuteBeanMethod (String targetClassName, String methodName, Class [] parameterTypes, Object [] args) {Class targetClass; try {targetClass = Class.forName (targetClassName) } catch (ClassNotFoundException e) {throw new RuntimeException ("class not found", e);} return excuteBeanMethod (targetClass, methodName, parameterTypes, args);} public static Object excuteBeanMethod (Class targetClass, String methodName, Class [] parameterTypes, Object [] args) {Object bean = SpringBootBeanUtil.getBean (targetClass) Method method = ReflectionUtils.findMethod (targetClass, methodName, parameterTypes); return ReflectionUtils.invokeMethod (method, bean, args);}} CheckedTransmitableUtil
Used to pass service parameters
Package com.proc.util;import com.alibaba.ttl.TransmittableThreadLocal;import com.proc.model.CheckedParam;public class CheckedTransmitableUtil {private static final TransmittableThreadLocal threadLocal = new TransmittableThreadLocal (); private CheckedTransmitableUtil () {} public static void set (CheckedParam checkedParam) {threadLocal.set (checkedParam);} public static CheckedParam getAndRemove () {CheckedParam checkedParam = threadLocal.get () ThreadLocal.remove (); return checkedParam;}} PrivateTransmitableUtil
To provide a basis for Aspect to judge whether to intercept or not.
Package com.proc.util;import com.alibaba.ttl.TransmittableThreadLocal;public class PrivateTransmitableUtil {private static final String CHECKED = "_ _ CHECKED__"; private static final TransmittableThreadLocal threadLocal = new TransmittableThreadLocal (); private PrivateTransmitableUtil () {} public static void set () {threadLocal.set (CHECKED) } / / approval procedure public static boolean isCheck () {String checked = threadLocal.get (); threadLocal.remove (); return CHECKED.equals (checked);}} some BeanPostProcess
Personality treatment after interception method
Package com.proc.bean;public interface PostProcess {/ / returns instructions, and displays String description (String tag, Class [] parameterTypes, Object [] args) on the page during approval; / / returns the substituted return value T retObject (String tag, Class [] parameterTypes, Object [] args);} TestCheckPostProcess
For testing
Package com.proc.bean;import org.springframework.stereotype.Component;@Componentpublic class TestCheckPostProcess implements PostProcess {@ Override public String description (String tag, Class [] parameterTypes, Object [] args) {return tag + "Test testCheck";} @ Override public String retObject (String tag, Class [] parameterTypes, Object [] args) {return tag + "return intercept response" }} Aspect annotations package com.proc.config;import static java.lang.annotation.ElementType.METHOD;import static java.lang.annotation.RetentionPolicy.RUNTIME;import java.lang.annotation.Retention;import java.lang.annotation.Target;import com.proc.bean.PostProcess;@Retention (RUNTIME) @ Target (METHOD) public @ interface Checked {String tag () default "" / * * @ see com.proc.util.JacksonCanonicalUtil * @ return * / String [] paramCanonical (); Class > postProcess ();} aspect class CheckedAoppackage com.proc.config;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature Import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import com.proc.bean.PostProcess;import com.proc.model.CheckedParam;import com.proc.model.ProcessDbModel;import com.proc.service.ProcessDbService;import com.proc.util.Base64Util;import com.proc.util.CheckedTransmitableUtil;import com.proc.util.PrivateTransmitableUtil;import com.proc.util.SpringBootBeanUtil;@Component@Aspectpublic class CheckedAop {@ Autowired private ProcessDbService processDbService / / the method @ Pointcut ("@ annotation (com.proc.config.Checked)") public void check () {} @ Around (value = "com.proc.config.CheckedAop.check () & & @ annotation (checked)") public Object around (ProceedingJoinPoint joinPoint, Checked checked) throws Throwable {MethodSignature signature = (MethodSignature) joinPoint.getSignature () Class [] parameterTypes = signature.getParameterTypes (); String methodName = signature.getMethod (). GetName (); Object [] args = joinPoint.getArgs (); if (PrivateTransmitableUtil.isCheck ()) {/ / after approval, execute the business code Object returnVal = joinPoint.proceed () Return returnVal;} else {/ / is not an approval operation. Block Class > postProcess = checked.postProcess (); PostProcess bean = SpringBootBeanUtil.getBean (postProcess) / / assemble persistent data ProcessDbModel dbModel = new ProcessDbModel (); dbModel.setTargetClassName (joinPoint.getTarget (). GetClass (). GetName ()); dbModel.setMethodName (methodName); String tag = checked.tag () CheckedParam checkedParam = CheckedTransmitableUtil.getAndRemove () If (checkedParam = = null | | checkedParam.getTagPageJs () = = null | | checkedParam.getTagPageJs () .isEmpty ()) {/ / is not the business called by the page. Use the annotated tag,data to save the parameters as service. In this case, the page needs to specifically parse the rendering String [] argStrs = Base64Util.toStrings (args). DbModel.setParamArgs (Base64Util.encodeZip (argStrs)); dbModel.setData (Base64Util.encode (argStrs));} else {tag = checkedParam.getTagPageJs (); dbModel.setParamArgs (Base64Util.encodeZip (args)) DbModel.setData (Base64Util.encode (checkedParam.getData (). ToArray (new String [0]));} dbModel.setTag (tag); dbModel.setParamTypes (Base64Util.encodeZip (checked.paramCanonical (); dbModel.setDescription (tag, parameterTypes, args)) / / persistent data processDbService.save (dbModel); return bean.retObject (tag, parameterTypes, args);} thread pool configuration
For testing
Package com.proc.config;import java.util.concurrent.Executor;import java.util.concurrent.ThreadPoolExecutor;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import com.alibaba.ttl.threadpool.TtlExecutors;@Configurationpublic class TaskExecutePoolConfig {@ Bean public Executor processExecutor () {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor () / / Core thread pool size executor.setCorePoolSize (10); / / maximum number of threads executor.setMaxPoolSize (10); / / queue capacity executor.setQueueCapacity (500); / / active time executor.setKeepAliveSeconds (60) / / thread name prefix executor.setThreadNamePrefix ("ProcessExecutor-"); executor.setRejectedExecutionHandler (new ThreadPoolExecutor.AbortPolicy ()); / / wait for all tasks to finish before closing thread pool executor.setWaitForTasksToCompleteOnShutdown (true); executor.initialize () / / wrapped in transmittable-thread-local, you can correctly pass data return TtlExecutors.getTtlExecutor (executor) to threads in the thread pool;}} persist service
Persistence is not really implemented for testing convenience
Package com.proc.service;import com.proc.model.ProcessDbModel;public interface ProcessDbService {void save (ProcessDbModel model); ProcessDbModel get ();} package com.proc.service.impl;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import com.proc.model.ProcessDbModel;import com.proc.service.ProcessDbService;@Componentpublic class ProcessDbServiceImpl implements ProcessDbService {private static final Logger log = LoggerFactory.getLogger (ProcessDbService.class) Private volatile ProcessDbModel model; @ Override public void save (ProcessDbModel model) {this.model = model; log.info (model.toString ());} @ Override public ProcessDbModel get () {return this.model;}} servicepackage com.proc.service;import com.proc.model.ProcessDbModel for approval Public interface ProcessCheckService {void process (ProcessDbModel model);} package com.proc.service.impl;import java.util.ArrayList;import java.util.List;import java.util.Objects;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Service;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.JavaType;import com.fasterxml.jackson.databind.json.JsonMapper;import com.proc.model.ProcessDbModel;import com.proc.service.ProcessCheckService;import com.proc.util.Base64Util Import com.proc.util.JacksonCanonicalUtil;import com.proc.util.PrivateTransmitableUtil;import com.proc.util.ProcessBeanUtil;@Servicepublic class ProcessCheckServiceImpl implements ProcessCheckService {private static final Logger log = LoggerFactory.getLogger (ProcessCheckServiceImpl.class); private static final JsonMapper MAPPER = new JsonMapper (); @ Override public void process (ProcessDbModel model) {PrivateTransmitableUtil.set (); String [] paramArgs = Base64Util.decodeZip (model.getParamArgs ()) String [] paramTypes = Base64Util.decodeZip (model.getParamTypes ()); List
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.