原理:利用spring bean 的监听,在所有的bean 初始化完成之后,能够接收到动作,在这会儿,可以利用spring获取到对应annotation、type的类,利用反射可以做到很多事情。
注意:spring的反射是cglib工具构建的,所以此时需要使用一个工具类获取到原始的javabean。
1、注册监听器
@Service @Lazy(true) public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
}
2、完整的代码(包含获取bean,反射)
package com.qysxy.erp.common.listener; import com.qysxy.erp.constants.ShiroConstants; import com.qysxy.erp.framework.shiro.annotation.PermissionDesc; import com.qysxy.erp.util.reflect.AopTargetUtils; import com.yizhilu.os.core.service.cache.MemCache; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Lazy; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Service; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * @Description 利用spring的监听获取bean, * @Author fuguangli businessfgl@163.com * @Create date: 2017/8/30 */ @Service @Lazy(true) public class ShiroApplicationListener implements ApplicationListener<ContextRefreshedEvent> { private MemCache memCache = MemCache.getInstance(); @Override public void onApplicationEvent(ContextRefreshedEvent event) { // ReflectionUtils.getAllDeclaredMethods() Map<String, String> savePerms = new HashMap<>(); Map<String, Object> beans = event.getApplicationContext().getBeansWithAnnotation(PermissionDesc.class); if (beans != null) { Set<String> keys = beans.keySet(); for (String key : keys) { Object o = null; try { o = AopTargetUtils.getTarget(beans.get(key)); } catch (Exception e) { e.printStackTrace(); } Class clazz = o.getClass(); Method[] methods = clazz.getMethods(); // Method[] methods = ReflectionUtils.getAllDeclaredMethods(o.getClass()); if (methods != null) { for (Method method : methods) { // method.setAccessible(true); Annotation[] annos = method.getAnnotations(); PermissionDesc permissionDesc = null; RequiresPermissions requiresPermissions = null; for (Annotation a : annos) { if (a.annotationType().equals(PermissionDesc.class)) { permissionDesc = (PermissionDesc) a; } if (a.annotationType().equals(RequiresPermissions.class)) { requiresPermissions = (RequiresPermissions) a; } } if (permissionDesc != null && requiresPermissions != null) { String desc = permissionDesc.value(); String[] perms = requiresPermissions.value(); for (String perm : perms) { /*TODO:此处应存入缓存 perm:desc*/ System.out.println(perm + ":" + desc); savePerms.put(perm, desc); } } } } } if (savePerms.size() != 0) { memCache.set(ShiroConstants.PERMS_KEY, savePerms);//默认存储24小时,用于新建权限的时候的权限钥匙 } } } }
3、获取原始javabean的工具类
package com.qysxy.erp.util.reflect; import org.springframework.aop.framework.AdvisedSupport; import org.springframework.aop.framework.AopProxy; import org.springframework.aop.support.AopUtils; import java.lang.reflect.Field; public class AopTargetUtils { /** * 获取 目标对象 * @param proxy 代理对象 * @return 目标对象 * @throws Exception */ public static Object getTarget(Object proxy) throws Exception { if(!AopUtils.isAopProxy(proxy)) { return proxy;//不是代理对象 } if(AopUtils.isJdkDynamicProxy(proxy)) { return getJdkDynamicProxyTargetObject(proxy); } else { //cglib return getCglibProxyTargetObject(proxy); } } private static Object getCglibProxyTargetObject(Object proxy) throws Exception { Field field = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); field.setAccessible(true); Object dynamicAdvisedInterceptor = field.get(proxy); Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); advised.setAccessible(true); Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget(); return target; } private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception { Field field = proxy.getClass().getSuperclass().getDeclaredField("h"); field.setAccessible(true); AopProxy aopProxy = (AopProxy) field.get(proxy); Field advised = aopProxy.getClass().getDeclaredField("advised"); advised.setAccessible(true); Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget(); return target; } }