【Spring】通过Spring收集自定义注解标识的方法

41 篇文章 0 订阅
25 篇文章 0 订阅

前言

需求:
用key找到对应的方法实现。使用注解的形式增量开发。

@MyComponent
public class Sample1 {

    @MyMethod(key = "key1")
    public String test2() {
        return "Shenzhen";
    }
}

任意时刻都能通过key来进行依赖查找

    @Test
    public void test() {
        Assert.notNull(myBeanFactory.getMethod("key1"), "key1对应的方法不能为空");
    }

实现思路:

  1. 声明自己的类注解,并要求被 Spring 收集
  2. 声明自己的方法注解,确保可以通过反射获取
  3. 借 Spring 的能力,容器启动收集bean完成后,把bean列表交给自己,用于自己的收集策略。

1. 声明注解

  • 类注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 继承Spring的注解,确保类能被Spring扫描
@Component
public @interface MyComponent {
	
    @AliasFor(
            annotation = Component.class
    )
    String value() default "";
}
  • 方法注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyMethod {
	// 用于依赖查找的key
    String key();
}

2. 使用 Spring 的工厂拓展

找到我们用注解标记的类、方法,Spring 收集完bean之后提供了拓展点供我们遍历这些bean。

  • BeanFactoryPostProcessor 接口
  • 其中 ConfigurableListableBeanFactory beanFactory 提供了容器
@Component
public class MyBeanFactory implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
 		// 找到所有注解标记的bean
        Map<String, Object> beanMap = beanFactory.getBeansWithAnnotation(MyComponent.class);

        beanMap.forEach((beanName, bean) -> {
            // 收集bean中用注解标记的方法 (方法先省略)
            // collectMethod(bean);
        });
    }
}

3. 收集策略

  • 收集策略可以很简单,这里就用一个Map收集
  • 用Spring的AnnotationUtils.findAnnotation(method, MyMethod.class) 命中标识的方法
  • 如果命中,则拿到注解中的key,收集key和Method的映射关系
    // 自己的容器
    private static final Map<String, Method> METHOD_MAP = new HashMap<>();
	
    public  Method getMethod(String key) {
        return METHOD_MAP.get(key);
    }

    private void collectMethod(Object bean) {
        Method[] methods = bean.getClass().getDeclaredMethods();

        Arrays.stream(methods)
                // 过滤: 只要MyMethod标识的方法 
                .filter(method -> Objects.nonNull(getAnnotation(method)))
                // 收集: 通过MyMethod的注解key,绑定依赖关系,放到自己的容器
                .forEach(method -> METHOD_MAP.putIfAbsent(getAnnotation(method).key(), method));
    }

    private static MyMethod getAnnotation(Method method) {
        return AnnotationUtils.findAnnotation(method, MyMethod.class);
    }

4. 完整的代码

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class MyBeanFactory implements BeanFactoryPostProcessor {
    
    private static final ConcurrentHashMap<String, Method> METHOD_MAP = new ConcurrentHashMap<>();

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 从Spring容器中获取所有MyController
        Map<String, Object> beanMap = beanFactory.getBeansWithAnnotation(MyComponent.class);

        beanMap.forEach((beanName, bean) -> {
            // 收集bean里面的所有可用方法
            collectMethod(bean);
        });
    }

    private void collectMethod(Object bean) {
        Method[] methods = bean.getClass().getDeclaredMethods();

        Arrays.stream(methods)
                // 过滤: 只要MyMethod标识的方法 
                .filter(method -> Objects.nonNull(getAnnotation(method)))
                // 收集: 通过MyMethod的注解key,绑定依赖关系,放到自己的容器
                .forEach(method -> METHOD_MAP.putIfAbsent(getAnnotation(method).key(), method));
    }

    private static MyMethod getAnnotation(Method method) {
        return AnnotationUtils.findAnnotation(method, MyMethod.class);
    }


    public  Method getMethod(String key) {
        return METHOD_MAP.get(key);
    }
}

后记

记录下用到的 Spring 的 api 和工具

  • 一个核心的接口方法获取bean容器
    BeanFactoryPostProcessor#postProcessBeanFactory

  • 获取指定注解修饰的类
    ConfigurableListableBeanFactory#getBeansWithAnnotation

  • 获取方法上的注解内容
    AnnotationUtils#findAnnotation

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Security允许我们使用自定义注解来标记需要进行访问控制的方法或类。通过自定义注解,我们可以在代码中清晰地标识出哪些部分需要进行权限验证。 以下是使用自定义注解来实现Spring Security的访问控制的一般步骤: 1. 创建一个自定义注解类,比如`@CustomAnnotation`,用于标记需要进行权限验证的方法或类。 ```java @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface CustomAnnotation { String value(); } ``` 2. 在Spring Security配置类中,通过`@EnableGlobalMethodSecurity`注解启用方法级别的安全配置,并指定自定义注解的扫描路径。 ```java @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { // ... } ``` 3. 创建一个切面类,用于处理自定义注解的逻辑。 ```java @Aspect @Component public class CustomAnnotationAspect { @Around("@annotation(com.example.CustomAnnotation)") public Object processCustomAnnotation(ProceedingJoinPoint joinPoint) throws Throwable { // 根据自定义逻辑进行权限验证等处理 // ... return joinPoint.proceed(); } } ``` 4. 在需要进行权限验证的方法或类上添加`@CustomAnnotation`注解。 ```java @RestController public class MyController { @CustomAnnotation("custom_permission") @GetMapping("/protected") public String protectedResource() { // ... } } ``` 通过以上步骤,我们可以使用自定义注解`@CustomAnnotation`来标记需要进行权限验证的方法或类,并在切面类中实现相应的逻辑。在访问这些被标记的方法或类时,Spring Security会自动触发切面类中的逻辑进行权限验证。 希望以上内容对你有所帮助!如果有任何疑问,请随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值