前段时间,为了校验接口数据方便,实现了一个简易的参数校验功能。通过参数上加注解并且配置spring aop实现的。
大概配置如下:
public Object ArroundParamCheck(ProceedingJoinPoint pj) throws Throwable{
if(null == pj){
log.info("传入的对象是空的!!!!!!!!!!");
}
log.info("参数校验开始================");
Object[] obs = pj.getArgs();
Response_CM resp = paramCheckService.paramCheck(obs);
log.info("参数校验结束==============" + resp.toString());
if(!CodeMsgConstant.CODE_000000.equals(resp.getRespCode())){
MethodSignature methodSg = (MethodSignature) pj.getSignature();
Class> returnType = methodSg.getReturnType();
return paramCheckService.getCheckResult(returnType, resp);
}
Object pjResult = pj.proceed();
return pjResult;
}
但是引入的系统时候需要显性的设置一个环绕增强,并且要在xml中配置切面切点。
使用过@Transactional的注解的应该都知道,只需要在方法或者类上标注@Transactional注解,就可以开启spring事务。使用起来比较便捷。为了作者练手,并且使用方便,于是便想参数校验做成类似模式。
使用@Transactional需要在spring xml下配置
这里的xml解析很简单
这里的xsd编写也很简单,因为只是一个标记,表示开启自动参数解析,只需要配置一个element,不需要额外的配置。
public class AvdNamespaceHandler extends NamespaceHandlerSupport{
@Override
public void init() {
registerBeanDefinitionParser("annotation-driven", new AvdAnnotationDrivenBeanDefinitionParser());
}
}
public class AvdAnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser{
public static final String AVD_ADVISOR_BEAN_NAME = "com.fosun.component.validate.interceptor.avdAdvisor";
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
configureAutoProxyCreator(element,parserContext);
return null;
}
private void configureAutoProxyCreator(Element element, ParserContext parserContext){
/**
* 如果必要开启自动创建代理对象
* 此方法可以将targetClass委托给spring让spring为符合切点的目标类自动创建代理对象
*/
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String avdAdvisorName = AVD_ADVISOR_BEAN_NAME;
if(!parserContext.getRegistry().containsBeanDefinition(avdAdvisorName)){
Object eleSource = parserContext.extractSource(element);
RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationAvdAttributeSource.class);
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
RootBeanDefinition interceptorDef = new RootBeanDefinition(AutoAvdInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryAutoAvdDefineAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisorDef.getPropertyValues().add("avdAttributeSource", new RuntimeBeanReference(sourceName));
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
parserContext.getRegistry().registerBeanDefinition(avdAdvisorName, advisorDef);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, avdAdvisorName));
parserContext.registerComponent(compositeDef);
}
}
}
http\://www.component.org/schema/avd = com.fosun.component.validate.config.AvdNamespaceHandler
spring.schemas
http\://www.component.org/schema/avd.xsd = com/fosun/component/validate/config/component-avd-1.0.xsd
maven-jar-plugin
target/classes/
false
xmlns:avd="http://www.component.org/schema/avd"
http://www.component.org/schema/avd http://www.component.org/schema/avd.xsd
继承StaticMethodMatcherPointcut表示这是一个静态切点。这个方法的主要目的就是匹配目标方法或者类是否标记了@AutoAvd注解。
public abstract class AutoAvdDefinePointcut extends StaticMethodMatcherPointcut{
@Override
public boolean matches(Method method, Class> targetClass) {
AvdAttributeSource aad = getAvdAttributeSource();
return (aad == null || aad.getAutoAvdDefine(method, targetClass) != null);
}
public abstract AvdAttributeSource getAvdAttributeSource();
}
实现MethodInterceptor接口,标识这是一个环绕增强。
public class AutoAvdInterceptor implements MethodInterceptor{
private final Logger log = LoggerFactory.getLogger(getClass());
@Autowired
ParamCheckService paramCheckService;
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// TODO Auto-generated method stub
// Class> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
Object[] obs = invocation.getArguments();
log.info("参数校验开始================");
Response_CM resp = paramCheckService.paramCheck(obs);
log.info("参数校验结束==============" + resp.toString());
if(!CodeMsgConstant.CODE_000000.equals(resp.getRespCode())){
Method method = invocation.getMethod();
Class> returnType = method.getReturnType();
return paramCheckService.getCheckResult(returnType, resp);
}
return invocation.proceed();
}
}
继承AbstractBeanFactoryPointcutAdvisor重写getPointcut()方法。
BeanFactoryAutoAvdDefineAdvisor中的AvdAttributeSource用来解析@AutoAvd注解的内容,
public class BeanFactoryAutoAvdDefineAdvisor extends AbstractBeanFactoryPointcutAdvisor{
private AvdAttributeSource avdAttributeSource;
private AutoAvdDefinePointcut aadPointcut = new AutoAvdDefinePointcut() {
@Override
public AvdAttributeSource getAvdAttributeSource() {
return avdAttributeSource;
}
};
public void setAvdAttributeSource(AvdAttributeSource avdAttributeSource) {
this.avdAttributeSource = avdAttributeSource;
}
@Override
public Pointcut getPointcut() {
return this.aadPointcut;
}
}
AnnotationAvdAttributeSource实现AvdAttributeSource来实现由@AutoAvd表示的内容。
回顾切点的matches()方法,利用了AvdAttributeSource的getAutoAvdDefine()方法来具体判读是否匹配切点。
public class AnnotationAvdAttributeSource implements AvdAttributeSource{
private AutoAvdAnnotationParser annotationParser;
public AnnotationAvdAttributeSource(){
this.annotationParser = new SpringAutoAvdAnnotationParser();
}
@Override
public AutoAvdDefine getAutoAvdDefine(Method method, Class> targetClass) {
/**
* 先这么写
*/
return computerAutoAvdDefine(method,targetClass);
}
private AutoAvdDefine computerAutoAvdDefine(Method method, Class> targetClass){
/**
* 不支持非public方法
*/
if ( !Modifier.isPublic(method.getModifiers())) {
return null;
}
Class> userClass = ClassUtils.getUserClass(targetClass);
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
AutoAvdDefine aad = findAutoAvdAnnotationDefine(specificMethod);
if (aad != null) {
return aad;
}
aad = findAutoAvdAnnotationDefine(specificMethod.getDeclaringClass());
if (aad != null) {
return aad;
}
if (specificMethod != method) {
aad = findAutoAvdAnnotationDefine(method);
if (aad != null) {
return aad;
}
return findAutoAvdAnnotationDefine(method.getDeclaringClass());
}
return null;
}
private AutoAvdDefine findAutoAvdAnnotationDefine(Method method){
return determineAutoAvdDefine(method);
}
private AutoAvdDefine findAutoAvdAnnotationDefine(Class> targetClass){
return determineAutoAvdDefine(targetClass);
}
private AutoAvdDefine determineAutoAvdDefine(AnnotatedElement ae){
return this.annotationParser.parseAutoAvdAnnotation(ae);
}
}
private void configureAutoProxyCreator(Element element, ParserContext parserContext){
/**
* 如果必要开启自动创建代理对象
* 此方法可以将targetClass委托给spring让spring为符合切点的目标类自动创建代理对象
*/
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String avdAdvisorName = AVD_ADVISOR_BEAN_NAME;
if(!parserContext.getRegistry().containsBeanDefinition(avdAdvisorName)){
Object eleSource = parserContext.extractSource(element);
RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationAvdAttributeSource.class);
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
RootBeanDefinition interceptorDef = new RootBeanDefinition(AutoAvdInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryAutoAvdDefineAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisorDef.getPropertyValues().add("avdAttributeSource", new RuntimeBeanReference(sourceName));/***/
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);/** */
parserContext.getRegistry().registerBeanDefinition(avdAdvisorName, advisorDef);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, avdAdvisorName));
parserContext.registerComponent(compositeDef);
}
}