如何编写像 ibatis Select 注释一样工作的 spring 自定义注释?
How to code spring custom annotation which works like ibatis Select annotation?
我正在尝试制作像 ibatis 这样的自定义注释 @Select
。
总之,目标是
- 将一些数据附加到方法具有自定义注释的参数中
先看看终点——ArtistNodeRepository.java
@Repository
public interface ArtistNodeRepository {
@CreateNode(tid = "artist")
public Node create(Map data) throws Exception;
}
想用CreateNode
注解做什么,把data.put("type", "artist")
放到参数Map里。
这是注释 - CreateNode.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface CreateNode {
String[] values() default "";
String tid();
}
为了控制器注释,我准备了这个BeanPostProcessor
- NodeAnnotationProcessor.java
@Component
public class NodeAnnotationProcessor implements BeanPostProcessor {
private ConfigurableListableBeanFactory configurableListableBeanFactory;
@Autowired
public NodeAnnotationProcessor(ConfigurableListableBeanFactory configurableListableBeanFactory) {
super();
this.configurableListableBeanFactory = configurableListableBeanFactory;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
this.scanNodeAnnotation(bean, beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// this.scanNodeAnnotation(bean, beanName);
return bean;
}
protected void scanNodeAnnotation(Object bean, String beanName){
this.configureMethodAction(bean);
}
private void configureMethodAction(Object bean){
Class<?> managedBeanClass = bean.getClass();
ReflectionUtils.MethodCallback methodCallback = new NodeMethodCallback(configurableListableBeanFactory, bean);
ReflectionUtils.doWithMethods(managedBeanClass, methodCallback);
}
}
我不清楚 MethodCallback
到 postProcessBeforeInitialization
或 postProcessAfterInitialization
的位置。在我看来,它会在 after
中,因为我试图操纵方法的参数
最后,这是 MethodCallback
- NodeMethodCallback.java
public class NodeMethodCallback implements ReflectionUtils.MethodCallback {
private Logger logger = LoggerFactory.getLogger(NodeMethodCallback.class);
private ConfigurableListableBeanFactory beanFactory;
private Object bean;
private static int AUTOWIRE_MODE = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
public NodeMethodCallback(ConfigurableListableBeanFactory beanFactory, Object bean) {
this.beanFactory = beanFactory;
this.bean = bean;
}
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
logger.info("doWith method info :: " + String.valueOf(bean) + "." + bean.getClass().getName());
/*
What I expected is Printing ArtistNodeRepository Class with create Method
But It prints something like ...
SessionFlashMapManager
DefaultRequestToViewNameTranslator
...
*/
try {
logger.info("When I call you :: " + method.getName()); // I expect method which contains @CreateNode annotation, but it is not ...
Annotation[] methodAnnotations = method.getDeclaredAnnotations();
boolean isTarget = false;
String tid = "";
for(Annotation anno : methodAnnotations) {
logger.info("annotation Class :: " + anno.getClass().getName());
if(isTarget) break;
if(anno instanceof CreateNode) {
logger.info("CreateNode annotation found");
CreateNode createNode = method.getDeclaredAnnotation(CreateNode.class);
tid = createNode.tid();
isTarget = true;
}
}
if(!isTarget) return;
ReflectionUtils.makeAccessible(method);
/*
Do Somthing with Parameter ...
Do Somthing with Parameter ...
Do Somthing with Parameter ...
Do Somthing with Parameter ...
Do Somthing with Parameter ...
*/
} catch (Exception e ){
logger.error("ERROR", e);
}
}
}
问题是...在 doWith
我找不到 ArtistNodeRepository
实例。
MethodCallback
和BeanPostProcessor
应该怎么做才能达到目的?
好的示例代码和好的答案一样好。
我认为您误解了 ReflectionUtils.doWithMethods
的用法。这意味着如果匹配回调,则迭代 class 方法。而不是在调用方法回调时。
public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) {
// Keep backing up the inheritance hierarchy.
Method[] methods = getDeclaredMethods(clazz);
for (Method method : methods) {
if (mf != null && !mf.matches(method)) {
continue;
}
try {
mc.doWith(method);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
}
}
if (clazz.getSuperclass() != null) {
doWithMethods(clazz.getSuperclass(), mc, mf);
}
else if (clazz.isInterface()) {
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
}
我认为你可以使用 aspect。像这样。
@Around("execution(public * org.springframework.data.jpa.repository.JpaRepository+.*(..))")
// @Around("@annotation(Repository)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
CreateNode createNode = method.getAnnotation(CreateNode.class);
if(createNode != null) {
Object[] args = joinPoint.getArgs();
// do your business
}
return joinPoint.proceed();
}
希望能帮到你
我正在尝试制作像 ibatis 这样的自定义注释 @Select
。
总之,目标是
- 将一些数据附加到方法具有自定义注释的参数中
先看看终点——ArtistNodeRepository.java
@Repository
public interface ArtistNodeRepository {
@CreateNode(tid = "artist")
public Node create(Map data) throws Exception;
}
想用CreateNode
注解做什么,把data.put("type", "artist")
放到参数Map里。
这是注释 - CreateNode.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface CreateNode {
String[] values() default "";
String tid();
}
为了控制器注释,我准备了这个BeanPostProcessor
- NodeAnnotationProcessor.java
@Component
public class NodeAnnotationProcessor implements BeanPostProcessor {
private ConfigurableListableBeanFactory configurableListableBeanFactory;
@Autowired
public NodeAnnotationProcessor(ConfigurableListableBeanFactory configurableListableBeanFactory) {
super();
this.configurableListableBeanFactory = configurableListableBeanFactory;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
this.scanNodeAnnotation(bean, beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// this.scanNodeAnnotation(bean, beanName);
return bean;
}
protected void scanNodeAnnotation(Object bean, String beanName){
this.configureMethodAction(bean);
}
private void configureMethodAction(Object bean){
Class<?> managedBeanClass = bean.getClass();
ReflectionUtils.MethodCallback methodCallback = new NodeMethodCallback(configurableListableBeanFactory, bean);
ReflectionUtils.doWithMethods(managedBeanClass, methodCallback);
}
}
我不清楚 MethodCallback
到 postProcessBeforeInitialization
或 postProcessAfterInitialization
的位置。在我看来,它会在 after
中,因为我试图操纵方法的参数
最后,这是 MethodCallback
- NodeMethodCallback.java
public class NodeMethodCallback implements ReflectionUtils.MethodCallback {
private Logger logger = LoggerFactory.getLogger(NodeMethodCallback.class);
private ConfigurableListableBeanFactory beanFactory;
private Object bean;
private static int AUTOWIRE_MODE = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
public NodeMethodCallback(ConfigurableListableBeanFactory beanFactory, Object bean) {
this.beanFactory = beanFactory;
this.bean = bean;
}
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
logger.info("doWith method info :: " + String.valueOf(bean) + "." + bean.getClass().getName());
/*
What I expected is Printing ArtistNodeRepository Class with create Method
But It prints something like ...
SessionFlashMapManager
DefaultRequestToViewNameTranslator
...
*/
try {
logger.info("When I call you :: " + method.getName()); // I expect method which contains @CreateNode annotation, but it is not ...
Annotation[] methodAnnotations = method.getDeclaredAnnotations();
boolean isTarget = false;
String tid = "";
for(Annotation anno : methodAnnotations) {
logger.info("annotation Class :: " + anno.getClass().getName());
if(isTarget) break;
if(anno instanceof CreateNode) {
logger.info("CreateNode annotation found");
CreateNode createNode = method.getDeclaredAnnotation(CreateNode.class);
tid = createNode.tid();
isTarget = true;
}
}
if(!isTarget) return;
ReflectionUtils.makeAccessible(method);
/*
Do Somthing with Parameter ...
Do Somthing with Parameter ...
Do Somthing with Parameter ...
Do Somthing with Parameter ...
Do Somthing with Parameter ...
*/
} catch (Exception e ){
logger.error("ERROR", e);
}
}
}
问题是...在 doWith
我找不到 ArtistNodeRepository
实例。
MethodCallback
和BeanPostProcessor
应该怎么做才能达到目的?
好的示例代码和好的答案一样好。
我认为您误解了 ReflectionUtils.doWithMethods
的用法。这意味着如果匹配回调,则迭代 class 方法。而不是在调用方法回调时。
public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) {
// Keep backing up the inheritance hierarchy.
Method[] methods = getDeclaredMethods(clazz);
for (Method method : methods) {
if (mf != null && !mf.matches(method)) {
continue;
}
try {
mc.doWith(method);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
}
}
if (clazz.getSuperclass() != null) {
doWithMethods(clazz.getSuperclass(), mc, mf);
}
else if (clazz.isInterface()) {
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
}
我认为你可以使用 aspect。像这样。
@Around("execution(public * org.springframework.data.jpa.repository.JpaRepository+.*(..))")
// @Around("@annotation(Repository)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
CreateNode createNode = method.getAnnotation(CreateNode.class);
if(createNode != null) {
Object[] args = joinPoint.getArgs();
// do your business
}
return joinPoint.proceed();
}
希望能帮到你