使用spring事件驱动机制,实现权限信息的自动收集存库
来源:互联网 发布:什么是网络消费贷款 编辑:程序博客网 时间:2024/04/30 00:46
最近在做权限管理,希望能够在容器初始化后,自动的将所有Controller上的url进行收集,并存放到权限表中,从而代替人工配置的方式。实现思路如下:
spring事件驱动机制+注解来实现。
spring事件驱动机制
spring在容器初始化之后,会触发ContextRefreshedEvent等事件,只要实现了ApplicationListener就可以捕获这个事件,这个时候,我们就可以做很多事情了,比如权限信息的提取,加载缓存等等,所以,我们的思路也是基于此的。
1、自定义注解
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
-
-
-
-
-
-
-
-
-
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.METHOD, ElementType.TYPE})
- public @interface PermissionPath {
-
- public String path() default "";
-
- public String moduleName() default "";
-
- public Operation operation();
- }
-
-
-
-
- public enum Operation {
- VIEW, UPDATE, ADD, DELETE
- }
2、实现ApplicationListener- import java.lang.reflect.Method;
- import java.util.Map;
- import java.util.Map.Entry;
-
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationListener;
- import org.springframework.context.event.ContextRefreshedEvent;
- import org.springframework.core.annotation.AnnotationUtils;
- import org.springframework.stereotype.Component;
-
- import com.chhliu.srd.rdcloud.annotation.PermissionPath;
-
-
-
-
-
-
-
-
- @Component
- public class ExtractPermissionInformationContext implements ApplicationListener<ContextRefreshedEvent> {
-
-
-
-
- @Override
- public void onApplicationEvent(ContextRefreshedEvent event) {
-
- System.out.println("===============开始提取权限信息================");
- System.out.println(event.getTimestamp());
-
- ApplicationContext applicationContext = event.getApplicationContext();
-
-
- Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(PermissionPath.class);
-
- if(null != beansWithAnnotation && !beansWithAnnotation.isEmpty()){
- for(Entry<String, Object> entry:beansWithAnnotation.entrySet()){
-
- Class<? extends Object> clz = entry.getValue().getClass();
- System.out.println("className:"+clz.getName());
-
- PermissionPath rm = AnnotationUtils.findAnnotation(clz, PermissionPath.class);
- System.out.println("class requestMapping:"+rm.path());
-
-
- Method[] methods = clz.getMethods();
- for(Method m:methods){
-
- if(m.isAnnotationPresent(PermissionPath.class)){
-
- PermissionPath ma = m.getAnnotation(PermissionPath.class);
- System.out.println("method requestMapping:"+ma.path());
- }
- }
- }
- }
- System.out.println("===============开始提取权限信息================");
- System.out.println(event.getTimestamp());
- }
- }
测试结果如下:- ===============开始提取权限信息================
- 1503631242290
- className:com.chhliu.srd.rdcloud.contractmanager.contractimport.controller.ContractImportController
- class requestMapping:/api/contractimport
- method requestMapping:updateMilston
- method requestMapping:queryDepartMent
- method requestMapping:queryByCondition
- method requestMapping:/fileUpload
通过上面的几个步骤,就基本实现了对权限信息的自动提取工作。那我们更近一步,spring的事件驱动机制是怎么工作的了,下面我们来看一个简单的示例。spring事件驱动流程:spring的事件传播机制 是基于观察者模式(Observer)实现的,它可以将 Spring Bean 的改变定义为事件 ApplicationEvent,通过 ApplicationListener 监听 ApplicationEvent 事件,一旦Spring Bean 使用 ApplicationContext.publishEvent( ApplicationEvent event )发布事件后,Spring 容器会通知注册在容器中的所有 ApplicationListener 接口的实现类,最后 ApplicationListener 接口实现类判断是否响应刚发布出来的 ApplicationEvent 事件。
从上面的流程原理这段描述中,我们可以发现几个关键类:1、ApplicationEvent,2、ApplicationListener
所以,在使用中,会有如下几个步骤:
1、建立事件类,即我们对外要发布的事件
2、建立监听类,监听第一步中发布的事件
3、发布事件
下面我们就通过一个简单的示例来逐步实现,示例需求:用户在注册成功之后,发布通知事件,通知采取短信和邮件两种通知方式,当事件监听器监听到发布的事件之后,通知用户注册成功。
建立事件类:通过继承ApplicationEvent类来实现,示例代码如下:
- package com.chhliu.application;
-
- import org.springframework.context.ApplicationEvent;
-
- public class SendEvent extends ApplicationEvent {
-
-
- private String title;
-
-
- private String sender;
-
-
- private String receiver;
-
-
- private String message;
-
-
-
- private static final long serialVersionUID = 1L;
-
- public SendEvent(String source) {
- super(source);
- }
-
- public SendEvent(String source, String title, String sender, String receiver, String message){
- super(source);
- this.title = title;
- this.sender = sender;
- this.receiver = receiver;
- this.message = message;
- }
- }
建立监听类,并监听事件,这里我们创建两个监听类,分别是短信通知监听和邮件通知监听。短信通知监听示例代码如下:
- package com.chhliu.application;
-
- import org.springframework.context.ApplicationListener;
- import org.springframework.stereotype.Component;
-
- @Component
- public class MessageSendListener implements ApplicationListener<SendEvent> {
-
- @Override
- public void onApplicationEvent(SendEvent event) {
- System.out.println(event.getSource()+":注册成功,发送短信通知!");
-
- System.out.println("发送短信到:"+event.getReceiver()+" 发送人:"+event.getSender()+" 短信内容:"+event.getMessage());
- }
-
- }
邮件通知监听示例代码如下:- package com.chhliu.application;
-
- import org.springframework.context.ApplicationListener;
- import org.springframework.stereotype.Component;
-
- @Component
- public class MailSendListener implements ApplicationListener<SendEvent> {
-
- @Override
- public void onApplicationEvent(SendEvent event) {
- System.out.println(event.getSource()+":注册成功,发送邮件通知!");
-
- System.out.println("发送邮件到:"+event.getReceiver()+" 发送人:"+event.getSender()+" 邮件内容:"+event.getMessage());
- }
-
- }
发布事件:经过上面的几个步骤,事件源和事件监听就做好了,剩下的就是发布事件了,spring中通过实现ApplicationContextAware类来发布事件,示例代码如下:- package com.chhliu.application;
-
- import org.springframework.beans.BeansException;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.stereotype.Service;
-
- @Service
- public class Registration implements ApplicationContextAware {
-
- private ApplicationContext applicationContext;
-
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- }
-
- public void register(final String username, final String password){
- System.out.println("调用后台注册服务!");
- System.out.println("注册成功,发送邮件和短信通知!");
-
-
- SendEvent se = new SendEvent(username, "注册会员成功通知", "chhliu", username, "恭喜您,注册我司会员成功,从今天开始,您将享受我司5星级服务!");
-
- this.applicationContext.publishEvent(se);
- }
- }
测试代码如下:- package com.chhliu;
-
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.test.context.SpringBootTest;
- import org.springframework.test.context.junit4.SpringRunner;
-
- import com.chhliu.application.Registration;
-
- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class SpringStudyApplicationTests {
-
- @Autowired
- private Registration regis;
-
- @Test
- public void contextLoads() {
- regis.register("xyh", "123456");
-
- }
-
- }
测试结果如下:- 调用后台注册服务!
- 注册成功,发送邮件和短信通知!
- xyh:注册成功,发送邮件通知!
- 发送邮件到:xyh 发送人:chhliu 邮件内容:恭喜您,注册我司会员成功,从今天开始,您将享受我司5星级服务!
- xyh:注册成功,发送短信通知!
- 发送短信到:xyh 发送人:chhliu 短信内容:恭喜您,注册我司会员成功,从今天开始,您将享受我司5星级服务!