一、spring容器初始化bean对象的顺序是listener-->filter-->servlet,其中
stattic>构造方法 > @Autowired > @PostConstruct。
故在static方法里面调用某个Bean,不可以用Autowired ,可以让通过ApplicationContext获取Bean。
二、如果在servlet初始化之前使用注解获取bean,是获取不到的,因为还没有注入进去。这时候我们可以通过以下几种方法来获取ApplicationContext:
1、方法一:
package com.demo.util;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 获得整个工程的上下文环境
*
*/
public final class SpringContextUtil {
/**
* 上下文
*/
private static ApplicationContext ctu;
/**
* 私有构造函数
*/
private SpringContextUtil() {
super();
}
public static void setApplicationContext(ApplicationContext applicationContext){
ctu = applicationContext;
}
/**
* 获得上下文
*
* @return ApplicationContext
*/
public static ApplicationContext getApplicationContext() {
return ctu;
}
}
public classUser{
private static Userservice userService;
private static RoleService roleService;
static{
userService= (Userservice ) SpringContextUtil.getApplicationContext().getBean("userService");
roleService= (RoleService ) SpringContextUtil.getApplicationContext().getBean("roleService");
}
public staic void addUser(User user,Role role)
userService.insert(user);
}
}
@Override方法也会在@ Autowired之前执行,这样使用到的@Autowired加载的bean会为null,故也需要像上面那样,如:
public class ExecuteAddJob implements org.quartz.Job{
private static JobService jobService;
private static JobSchedule jobSchedule;
static{
jobService = (JobService) SpringContextUtil.getApplicationContext().getBean("jobService");
jobSchedule = (JobSchedule) SpringContextUtil.getApplicationContext().getBean("jobSchedule");
}
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
//获取未执行过的job
List jobList = jobService.getUnExecutedJobs();
if (CollectionUtils.isNotEmpty(jobList)) {
for (Job job : jobList) {
try {
jobSchedule.addJob(job);
//添加到schedule后,状态更新为已执行
job.setState(JobStatus.EXECUTE.getStatus());
jobService.updateJob(job);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
}
}
启动类:
@SpringBootApplication
public class SecurityApplication {
public static void main(String args[]){
ApplicationContext applicationContext = SpringApplication.run(SecurityApplication.class, args);
//实例化上下文对象
SpringContextUtil.setApplicationContext(applicationContext);
}
}
如果是在filter过滤器中获取spring的bean:
Bean都是被Spring容器管理的,使用的时候,直接通过注解@Autowired,注入即可
在Filter中,不能使用@Autowired注解注入,通过注解获取到的为null
Filter并没有被Spring容器管理,它是运行在Tomcat上的,是由Servlet来管理的
ServletContext sc = req.getSession().getServletContext();
XmlWebApplicationContext cxt = (XmlWebApplicationContext) WebApplicationContextUtils.findWebApplicationContext(sc);
redisClient = (RedisClient) cxt.getBean("redisClient");
Animal dog = (Animal) SpringContextUtil.getApplicationContext()
.getBean(Objects.requireNonNull(query.getType()));
public interface Animal {
}
@Service("dog)
public class Dog implements Animal {
}
2、方法二:
package com.demo.factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextRegister implements ApplicationContextAware {
private static Logger logger = LoggerFactory.getLogger(ApplicationContextRegister.class);
private static ApplicationContext APPLICATION_CONTEXT;
/**
* 设置spring上下文
* @param applicationContext spring上下文
* @throws BeansException
* */
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
logger.debug("ApplicationContext registed-->{}", applicationContext);
DefaultBeanFactory.setSpringApplicationContext(applicationContext);
APPLICATION_CONTEXT = applicationContext;
}
/**
* 获取容器
* @return
*/
public static ApplicationContext getApplicationContext() {
return APPLICATION_CONTEXT;
}
/**
* 获取容器对象
* @param type
* @param
* @return
*/
public static T getBean(Class type) {
return APPLICATION_CONTEXT.getBean(type);
}
}
package com.demo.factory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DefaultBeanFactory {
private static ApplicationContext context = null;
private static DefaultBeanFactory instance = null;
private static Object lock = new Object();
private DefaultBeanFactory(String filepath){
try {
context = new ClassPathXmlApplicationContext(filepath);
} catch (Exception e) {
}
}
@SuppressWarnings("static-access")
private DefaultBeanFactory(ApplicationContext context){
try {
this.context = context;
} catch (Exception e) {
}
}
public static void setSpringApplicationContext(ApplicationContext context){
synchronized (lock) {
instance = new DefaultBeanFactory(context);
}
}
public static DefaultBeanFactory getInstance() {
if(instance == null || context == null){
throw new RuntimeException("Spring context is null!");
}
return instance;
}
public static DefaultBeanFactory getInstance(String filepath) {
synchronized (lock) {
instance = new DefaultBeanFactory(filepath);
}
return instance;
}
public Object getBean(String name) {
return context.getBean(name);
}
}
bean获取类:
package com.demo.factory;
import com.demo.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ServiceFactory {
private static Logger logger = LoggerFactory.getLogger(ServiceFactory.class);
private static ServiceFactory instance = new ServiceFactory();
private final String USER_SERVICE_BEAN="userService";
public ServiceFactory() {
// TODO Auto-generated constructor stub
}
public static ServiceFactory getInstance() {
if (instance == null) {
instance = new ServiceFactory();
}
return instance;
}
public UserService createUserService() {
try {
return (UserService) DefaultBeanFactory.getInstance().getBean(USER_SERVICE_BEAN);
} catch (Exception e) {
throw new RuntimeException("创建 USER_SERVICE BEAN 异常", e);
}
}
}
启动类不需要做修改:
@SpringBootApplication
@MapperScan("com.demo.dao")
public class JobStart {
public static void main(String[] args) {
SpringApplication.run(JobStart.class, args);
}
}
应用:
public class MyDbJob implements Job{
private static UserService userService;
static {
userService = ServiceFactory.getInstance().createUserService();
}
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.print("执行db");
User user = new User();
user.setName("名称");
user.setAge(18);
userService.insert(user);
}
}
3、方法三:
以上方法在BasicHttpAuthenticationFilter中获取不到bean,
以下方法测试可用:
ServletContext servletContext = request.getServletContext();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
redisClient = (RedisClient) context.getBean("redisClient");
应用:
public class JwtFilter extends BasicHttpAuthenticationFilter {
private static RedisClient redisClient;
private AntPathMatcher antPathMatcher =new AntPathMatcher();
/* static {
//获取不到bean,报错spring context is null
redisClient = ServiceFactory.getInstance().createRedisClient();
}*/
/**
* 执行登录认证(判断请求头是否带上token)
* @param request
* @param response
* @param mappedValue
* @return
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
System.out.println("JwtFilter-->>>isAccessAllowed-Method:init()");
//如果请求头不存在token,则可能是执行登陆操作或是游客状态访问,直接返回true
if (isLoginAttempt(request, response)) {
return true;
}
//如果存在,则进入executeLogin方法执行登入,检查token 是否正确
try {
executeLogin(request, response);return true;
} catch (Exception e) {
throw new AuthenticationException("Token失效请重新登录");
}
}
/**
* 判断用户是否是登入,检测headers里是否包含token字段
*/
@Override
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
ServletContext servletContext = request.getServletContext();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
redisClient = (RedisClient) context.getBean("redisClient");
System.out.println("JwtFilter-->>>isLoginAttempt-Method:init()");
HttpServletRequest req = (HttpServletRequest) request;
if(antPathMatcher.match("/login",req.getRequestURI())){
return true;
}
String token = req.getHeader(CommonConstant.ACCESS_TOKEN);
if (token == null) {
return false;
}
Object o = redisClient.get(CommonConstant.PREFIX_USER_TOKEN,token);
if(ObjectUtils.isEmpty(o)){
return false;
}
System.out.println("JwtFilter-->>>isLoginAttempt-Method:返回true");
return true;
}
/**
* 重写AuthenticatingFilter的executeLogin方法丶执行登陆操作
*/
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
System.out.println("JwtFilter-->>>executeLogin-Method:init()");
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = httpServletRequest.getHeader(CommonConstant.ACCESS_TOKEN);//Access-Token
JwtToken jwtToken = new JwtToken(token);
// 提交给realm进行登入,如果错误他会抛出异常并被捕获, 反之则代表登入成功,返回true
getSubject(request, response).login(jwtToken);return true;
}
/**
* 对跨域提供支持
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
System.out.println("JwtFilter-->>>preHandle-Method:init()");
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
// 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
}
4、方法四:
BeanFactory factory = WebApplicationContextUtils
.getRequiredWebApplicationContext(request.getServletContext());
myService= (LogModuleService) factory.getBean("myService");
如:
package com.demo.service.impl;
import com.demo.service.LogModuleService;
import org.springframework.stereotype.Service;
@Service("logModuleService")
public class LogModuleServiceImpl implements LogModuleService {
@Override
public void insertLogModuleRecord(String moduleCode) {
System.out.println("访问模块"+moduleCode);
}
}
拦截器获取这个Bean:
package com.demo.interceptor;
import com.demo.service.LogModuleService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class LogModuleInterceptor implements HandlerInterceptor{
private LogModuleService logModuleService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
......
String moduleCode = null;
BeanFactory factory = WebApplicationContextUtils
.getRequiredWebApplicationContext(request.getServletContext());
logModuleService = (LogModuleService) factory.getBean("logModuleService");
logModuleService.insertLogModuleRecord(moduleCode);
}
return true;
}
}