ApplicationContextAware用法
当一个类实现了这个接口之后,这个类就可以方便的获得ApplicationContext对象(spring上下文),Spring发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContext(参数)方法,调用该方法时,会将容器本身ApplicationContext对象作为参数传递给该方法。
package com.lyj.demo.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author 凌兮
* @date 2020/5/18 15:39
* 全局上下文
*/
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return context;
}
/**
* 通过name获取 Bean
* @param name beanName
* @return Object
*/
public static Object getBean(String name){
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> requiredType) throws BeansException{
return getApplicationContext().getBean(requiredType);
}
}
InitialzingBean用法
当一个类实现这个接口之后,Spring启动后,初始化Bean时,若该Bean实现InitialzingBean接口,会自动调用afterPropertiesSet()方法,完成一些用户自定义的初始化操作。
package com.lyj.demo.studySpringBoot.init;
import com.lyj.studySpringBoot.entity.Student;
import org.springframework.beans.factory.InitializingBean;
public class SpringBeanInit implements InitializingBean {
private Integer id;
private String name;
private Integer age;
private boolean sex;
private Student student;
/** 这里进行优先调用初始化一些参数
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("this is bean init set student data");
Student student = new Student(id,name,age,sex);
this.student = student;
}
public void testInit(){
System.out.println("this is bean web.xml init-method invock");
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
同样配置Bean的时候使用init-method也可以实现类似的操作
<bean id = "springBeanInit02" class = "com.lyj.studySpringBoot.init.SpringBeanInit" init-method="testInit">
<property name="id" value="#{1111111}" />
<property name="name" value="${test.springEL}" />
<property name="age" value="#{10+8}" /> // SpringEL表达式
<property name="sex" value="false" />
</bean>
在spring初始化bean的时候,如果该bean是实现了InitializingBean接口,并且同时配置文件中指定了init-method,系统则是先调用afterPropertiesSet方法,然后在调用init-method中指定的方法。
重要提醒
Spring是通过反射来调用init-method指定方法,而实现InitializingBean接口是直接调用afterPropertiesSet方法,所以后者效率高,但使用init-method方式减少了对Spring的依赖
如果调用afterPropertiesSet方法时报错,则不会再调用init-method指定的方法
pix框架使用案例:(接口使用@Inner注解,如果url是path variable 则替换为'*',跳过安全校验,访问资源(例如/user/{id},替换为/user/*)。其实有安全问题(造成/user/x,user/xx等接口都跳过了校验),这里暂且不管,只学习InitializingBean与ApplicationContextAware的用法。)
/**
* @author lengleng
* @date 2020-03-11
* <p>
* 资源服务器对外直接暴露URL,如果设置contex-path 要特殊处理
*/
@Slf4j
@ConfigurationProperties(prefix = "security.oauth2.ignore")
public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware {
private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
private static final String ASTERISK = "*";
private ApplicationContext applicationContext;
@Getter
@Setter
private List<String> urls = new ArrayList<>();
@Override
public void afterPropertiesSet() {
RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
map.keySet().forEach(info -> {
HandlerMethod handlerMethod = map.get(info);
// 获取方法上边的注解 替代path variable 为 *
Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class);
Optional.ofNullable(method).ifPresent(inner -> info.getPatternsCondition().getPatterns()
.forEach(url -> urls.add(ReUtil.replaceAll(url, PATTERN, ASTERISK))));
// 获取类上边的注解, 替代path variable 为 *
Inner controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Inner.class);
Optional.ofNullable(controller).ifPresent(inner -> info.getPatternsCondition().getPatterns()
.forEach(url -> urls.add(ReUtil.replaceAll(url, PATTERN, ASTERISK))));
});
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.applicationContext = context;
}
}