BeanPostProcessor,bean,Aware,ApplicationContextAware RequestContextHolder
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); String token = request.getHeader(""); @Autowired protected HttpServletRequest request;
SuperScheduledPostProcessor implements BeanPostProcessor, ApplicationContextAware {
BeanPostProcessor该接口我们也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在初始化方法的前后添加我们自己的逻辑
通过 BeanPostProcessor 解析Scheduled注解,收集指定注解的类、方法名
implements ApplicationRunner, ApplicationContextAware {
ApplicationRunner springBoot项目启动时候,有时候需要再启动之后直接执行某一段代码。这个时候就用到了 ApplicationRunner 这个类
@Override
public void run(ApplicationArguments args) {
SuperScheduledManager.addScheduled
threadPoolTaskScheduler.schedule(runnable, new CronTrigger(scheduledSource.getCron()));
@EnablexxxJmsMqListener 注解中引入 @Import(ImportxxxJsmListenerBeanDefinition.class)
ImportxxxJsmListenerBeanDefinition implements ImportBeanDefinitionRegistrar, EnvironmentAware {//获取注解依次处理
public class SuperScheduledPostProcessor implements BeanPostProcessor, ApplicationContextAware { ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName); } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { Method[] methods = bean.getClass().getDeclaredMethods(); MyTestService myTestService; //循环处理对每个方法逐一处理 if (methods.length > 0) { for (Method method : methods) { //3.尝试在该方法上获取@Scheduled注解(SpringBoot的定时任务注解) ProcessTest annotation = method.getAnnotation(ProcessTest.class); //如果无法获取到@Scheduled注解,就跳过这个方法 if (annotation == null) { continue; } System.out.println(beanName+" "+method.getName()+" "+annotation.value()); myTestService = (MyTestService) this.applicationContext.getBean("myTestService"); if(myTestService.getMap() == null){ myTestService.setMap(new HashMap()); } myTestService.getMap().put(beanName,method.getName()+":"+annotation.value()); } } return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName); } } @Configuration @Import(SuperScheduledPostProcessor.class)// 等同于注册实例到容器 public class ConfigTest { @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ProcessTest { String value(); } @Service public class MyTestService { private Map map ; public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } } @Service public class MyTestMain { @ProcessTest("mytestMainValue") public void mytestMainMethod(){ } } @Service public class MyTest { public String s ="s"; @ProcessTest("myTestValue") public void myTestMethod(){ } } 测试 @Autowired MyTestService myTestService; @RequestMapping("/hello") @ResponseBody public String hello() { System.out.println("***************hello1:"+myTestService.getMap()); return "hello:"; }
BeanNameAware 获得到容器中Bean的名称
BeanFactoryAware 获得当前bean Factory,从而调用容器的服务
ApplicationContextAware 当前的application context从而调用容器的服务
MessageSourceAware 得到message source从而得到文本信息
ApplicationEventPublisherAware 应用时间发布器,用于发布事件
ResourceLoaderAware 获取资源加载器,可以获得外部资源文件
public class SuperScheduledApplicationRunnerMy implements ApplicationRunner{ @Override public void run(ApplicationArguments args) { //服务启动后需要执行的代码 这个接口表面上的作用就是让实现这个接口的bean知道自己在spring容器里的名字,而且听官方的意思是这个接口更多的使用在spring的框架代码中,实际开发环境应该不建议使用,因为spring认为bean的名字与bean的联系并不是很深 @Service public class BeanNameAwareTest implements BeanNameAware { @Override public void setBeanName(String s) { System.out.println("BeanNameAwareTest************"+s); } } @Service public class BeanFactoryAwareTest implements BeanFactoryAware { @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { MyTestService myTestService = beanFactory.getBean(MyTestService.class); myTestService.myService(); } } @Service public final class SettingsBean implements ResourceLoaderAware { private static Properties settings; private ResourceLoader loader; private static final String SETTINGS_FILE = "classpath:/config/settings.properties"; @Override public void setResourceLoader(ResourceLoader loader) { this.loader = loader; try { FileInputStream inputStream = new FileInputStream(loader.getResource(SETTINGS_FILE).getFile()); settings = new Properties(); settings.load(inputStream); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } public void save() { try { OutputStream outputStream = new FileOutputStream(loader.getResource(SETTINGS_FILE).getFile()); settings.store(outputStream, ""); outputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public Properties getSettings() { return settings; } public void setProperty(String key, String value) { settings.setProperty(key, value); } public static String getProperty(String key) { return settings.getProperty(key); } public double getDouble(String key) { return Double.parseDouble(settings.getProperty(key)); } public int getInteger(String key) { return Integer.parseInt(settings.getProperty(key)); } }
@Configuration public class ConfigTest { @Bean public MyTest myTestsssss(){//生产myTestsssss实例id return new MyTest(); } @Bean public MyTestMain myTestMainxxxx(MyTest myTestsssss){ System.out.println("*********************myTestsssss:"+myTestsssss+","+myTestsssss.s); System.out.println("*********************myTestsssss():"+myTestsssss()); return new MyTestMain(); } @Bean public ResultVo resultVo(){ System.out.println("*********************"); myTestMainxxxx(new MyTest()); return null; } 实例化完成后,不会重复实例化 *********************myTestsssss:cn.com.domain.MyTest@18eec010,s *********************myTestsssss():cn.com.domain.MyTest@18eec010 *********************
java的注解实现的核心技术是反射,让我们通过一些例子以及自己实现一个注解来理解它工作的原理
@Override注解使用java官方提供的注解,它的定义里面并没有任何的实现逻辑。注意,所有的注解几乎都是这样的,注解只能是被看作元数据,它不包含任何业务逻辑。 注解更像是一个标签,一个声明,表面被注释的这个地方,将具有某种特定的逻辑,那么注解的功能是如何实现的呢?答案必然是别的某个地方对这个注解做了实现。以@Override注解为例,他的功能是重写一个方法,而他的实现者就是JVM,java虚拟机,java虚拟机在字节码层面实现了这个功能
我们自己想定义一个独一无二的注解的话,则我们需要自己为注解写一个实现逻辑,换言之,我们需要实现自己注解特定逻辑的功能。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SimpleAnnotation {
String value();
}
它的目标注释对象是方法,保留策略是在运行期间。
在Spring的众多注解中,经常会发现很多注解的不同属性起着相同的作用,比如@RequestMapping的value属性和path属性,这就需要做一些基本的限制,比如value和path的值不能冲突,比如任意设置value或者设置path属性的值,都能够通过另一个属性来获取值等等。为了统一处理这些情况,Spring创建了@AliasFor标签。