问题起因:
在spring-security配置类里面,配置了一个权限验证服务,此服务通过security内部某种机制注入spring,配置时,使用new对象的形式。
在类全局变量使用@value的形式希望加载配置项里面的配置,但是后台又希望放一些硬编码的默认配置,直接在构造方法里面追加配置,发现变量为null。此时类的相关配置还没装载完毕,在postcontract下,可以正常获取。
探究过程:
借此机会,平时有项目启动时需要初始全局数据,或者启动时做数据处理数据的需求,稍微延伸一下,看下常用的一些监听,容器等的加载顺序,一次性弄清楚(欢迎大家补充)
本次考察范围包括:
1、 基于servilet的:监听器,过滤器,servlet,启动项目时加载顺序。这些类一般就提供了明确的初始方法,销毁方法,类内部的生命周期非常明确。
2、 spring中的:配置类,服务类,控制器类,启动时加载顺序。因为这些类没有明显的,类似servlet体系里面生命周期方法,需要添加一些方法或实现,来做具体监控,以便于以后在合适的时机做合适的事情。
3、 容器类的启用节点:
- 构造方法
- @PostConstruct标注方法,此方法会在类的依赖关系加载完毕后被执行;
- 类继承InitializingBean接口,实现afterPropertiesSet方法,此方法在这个类所有配置,相关属性全部填装完毕后执行;
- 类继承ApplicationListener<ContextRefreshedEvent>接口,实现onApplicationEvent方法,这是处理容器事件的一个回调方法,项目启动过程中,会有2次进入。
测试用例:
测试准备
1、正在开发spring-cloud项目,就用这个项目来测好了;
2、在spring-coud项目里面测试servlet的东西,要在启动类添加@ServletComponentScan注解;
@SpringBootApplication
@ServletComponentScan//启动扫描servlet相关
public class App
{
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
}
}
3、开始在工程里面添加测试类,和输出信息,通过输出来观察顺序;
监听器
@WebListener
public class TestListener implements ServletContextListener{
public TestListener() {
System.out.println("TestListener=====================new");
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("Listener=========================contextDestroyed");
}
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Listener=========================contextInitialized");
}
}
过滤器
@WebFilter(filterName="TestFilter",value="/*")
public class TestFilter implements Filter{
public TestFilter() {
System.out.println("TestFilter======================new");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
System.out.println("TestFilter =========================init");
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("TestFilter =========================do filter");
}
}
Servlet类
@WebServlet(name = "firstServlet", urlPatterns = "/firstServlet")
public class ServletTest extends HttpServlet{
public ServletTest(){
System.out.println("ServletTest=======================new");
}
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
System.out.println("servletTest===================== init");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servletTest======================do get");
super.doGet(req, resp);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("servletTest=====================destroy");
}
}
spring配置类
package com.mbap.auth.config;
import javax.annotation.PostConstruct;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TestConfig {
private String id;
public TestConfig() {
super();
System.out.println("myconfig========================new");
}
@PostConstruct
public void myCoinfig() {
System.out.println("myconfig========================postConstruct");
}
}
spring 服务类
package com.mbap.auth.service;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Service;
@Service
public class TestService implements InitializingBean ,ApplicationListener<ContextRefreshedEvent>{
public TestService() {
System.out.println("TestService================================构造方法new");
// permitAll.add("[GET]/mbap-pp/rest/system/menu/permission/permissionTree");
}
@PostConstruct
public void init() {
System.out.println("TestService================================PostConstruct");
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("TestService===================on event");
if(event.getApplicationContext().getParent() == null){//root application context 没有parent
System.out.println("TestService======projectName-servlet context");
}
if(event.getApplicationContext().getDisplayName().equals("Root WebApplicationContext")){
System.out.println("TestService======root application context");
}
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("TestService================================afterPropertiesSet");
}
}
spring 控制器
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.mbap.auth.service.TestService;
@RestController
@RequestMapping("/test/")
public class TestController {
@Autowired
private TestService service;
@PostConstruct
private void init() {
System.out.println("TestController==================postConstruct");
}
}
控制台输出
ServletTest=======================new
TestFilter======================new
TestListener=====================new
//由此看出servlet类加载顺序servlet/Filter/Listener
Listener=========================contextInitialized
TestFilter =========================filter init
//这里输出结果看出:servlet类初始化Listener>Filter
//spring相关开始初始化启动
myconfig========================new
myconfig========================postConstruct
TestService================================构造方法new
TestService================================PostConstruct
TestService================================afterPropertiesSet
TestController==================postConstruct
TestService===================on event
//===>在浏览器访问servlet页面,查看控制台
servletTest ========================init
TestFilter =========================do filter
servletTest ========================do Get(预期输出,但是没有输出,还没弄清楚咋回事,有空再看)
结论
参考资料