美文网首页
2.spring面试解答

2.spring面试解答

作者: Junma_c631 | 来源:发表于2020-12-02 17:21 被阅读0次

    SpringIOC

    1.解析配置类Config.class,获取配置类上面@componetScan注解的值package

    2.扫描package下的类,并把带有@Compent注解的以及继承自@Compent注解的类,解析成
    beanDefintion(bean定义),解析类中定义的@Scope @Lazy 等注解设置为定义的属性,解析完成
    放入容器中beanDefintionMap中

    3.实例化非懒加载的单例bean
    3.1对beanDefintionMap中的bean定义进行合并,放入合并后的bean定义容器中mergedBeanDefinitionMap
    3.2.循环遍历合并后的bean定义容器,
    根据bean定义中的scope属性查看是否是单例的bean,并查看是否是懒加载,实例化单例非懒加载的bean
    实例化之后进行属性填充,
    属性填充之后判断bean是否实现了Aware接口,调用Aware接口的实现方法
    然后调用bean的初始化方法进行初始化
    如果有切面,需要进行动态代理,生成代理bean
    把生成的bean放入单例池。bean的实例化过程在spring中是调用bean的不同的后置处理器来完成的。

    Spring AOP

    切面(创建一个切面类@Aspect,切面类里面定义了很多切点)
    切点:@PointCut(com.methd*) 连接点的集合
    连接点 就是需要切入的某个方法
    通知 切入的时机+切入的逻辑。@Before("myPointCut")

    @Aspect
    public class MyAspect {
        //定义一个切点
        @Pointcut("execution(* mjw.spring.aop.dao.*.*(..))")
        public void myPointCut(){
        }
        //定义通知
        @Before("myPointCut()")
        public void beforeAdv(){
            System.out.println("before 通知");
        }
        //也可以吧切点和通知合并配置
        @Before("execution(* mjw.spring.aop.service.*.*(..))")
        public void beforeAdv2(JoinPoint joinPoint){
            System.out.println("before execution");
        }
    }
    

    单例作用域的bean中引入原型作用域的Bean的问题

    单例作用域的bean中引入原型作用域的Bean的问题
    如果一个单例的bean中引用了一个多例的bean,这时候这个多例的bean只会被注入一次,所以达不到多例的效果了,如果想要达到多例的效果可以如下作用:

    @Scope("prototype")
    @Compent
    Class Command{
    }
    
    
    package fiona.apple;
    
    // Spring-API imports
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    @Component
    public class CommandManager implements ApplicationContextAware {
        @AutoWared
        private ApplicationContext applicationContext;
    
        public Object process(Map commandState) {
            // grab a new instance of the appropriate Command
            Command command = createCommand();
            // set the state on the (hopefully brand new) Command instance
            command.setState(commandState);
            return command.execute();
        }
    
        protected Command createCommand() {
            // 这样每次调用就可以创建一个新的实例,
            //但是这种做法 代码侵入性太高
            return this.applicationContext.getBean("command", Command.class);
        }
    
        public void setApplicationContext(
                ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    }
    
    @Scope("prototype")
    @Component
    Class Command{
    }
    package fiona.apple;
    
    // Spring-API imports
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    @Component
    public abstract class CommandManager{
        @LookUp
    public abstract Command createCommand();
        public Object process(Map commandState) {
            // grab a new instance of the appropriate Command
            Command command = createCommand();
            // set the state on the (hopefully brand new) Command instance
            command.setState(commandState);
            return command.execute();
        }
    }
    

    springMVC

    1.  请求进来之后会进入到doDispatch()方法中。
    2.  根据request从handlermappings循环获取handler,并构建成一个调用链对象
           HandlerExecutionChain,调用链中包含handler对象以及拦截器。
          注意:springMVC中生命一个controller有三种方式:@Controller注解\实现
          Controller接口\实现HttpRequestHandler接口分别对应三种映射器来获取
          handler对象。这三种方式@Contoller是把对象中的方法解析成一个个handler;
          其余两种其实就是从Spring容器中获取真实的对象。
    3.  根据request从匹配出适合的适配器,适配器也有三种分别对应不同的Controller类型,
    4.  Chain.applyPreHandle()按顺序调用拦截器
    5.  Ha.hand(hand) –通过适配器调用handle对应的方法。其中@Controller类型是通过反射调用,
       期间会通过策略模式,根据不同类型的参数调用不同的参数解析器从request中解析参 
       数值,然后通过反射调用controller的方法;根据方法的返回值以及方法上有没有加@ResponseBody注解,
       来判断是走视图解析器还是走消息转换器。
    6.  Chain.applyPostHandle()调用拦截器
    7.  调用视图解析器渲染参数以及页面跳转。
    

    手写springMVC

    1.tomcat启动类

    package com.luban.springmvc;
    import com.luban.springmvc.servlet.DispatcherServlet;
    import org.apache.catalina.Context;
    import org.apache.catalina.core.StandardContext;
    import org.apache.catalina.startup.Tomcat;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.ComponentScan;
    
    @ComponentScan("com.luban")
    public class Start {
    
        public static void main(String[] args) throws Exception {
            Tomcat tomcat = new Tomcat();
            tomcat.setPort(8080);
            tomcat.addWebapp("/", "D:\\workspace\\springmvc\\src\\main\\webapp");
            tomcat.start();
            tomcat.getServer().await();
        }
    }
    

    2.基于servlet3.0规范利用SPI机制web容器启动完毕之后加载DispatcherServlet


    image.png
    #com.luban.springmvc.init.Myinit
    package com.luban.springmvc.init;
    
    import com.luban.springmvc.Start;
    import com.luban.springmvc.servlet.DispatcherServlet;
    import org.apache.jasper.servlet.JspServlet;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    import javax.servlet.ServletContainerInitializer;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletRegistration;
    import java.util.Set;
    
    //SPI
    public class Myinit implements ServletContainerInitializer{
    
        @Override
        public void onStartup(Set<Class<?>> c,ServletContext servletContext) {
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Start.class);
            DispatcherServlet servlet = new DispatcherServlet(ac);
            ServletRegistration.Dynamic dy = servletContext.addServlet("app",servlet);
            dy.setLoadOnStartup(1);
            dy.addMapping("*.do");
          /*  JspServlet jspServlet = new JspServlet();
            ServletRegistration.Dynamic dy1 = servletContext.addServlet("app1",jspServlet);
            dy1.setLoadOnStartup(2);
            dy1.addMapping("*.jsp");*/
        }
    }
    
    

    3.DispatcherServlet

    package com.luban.springmvc.servlet;
    
    import com.luban.springmvc.init.handlerAdapter.HandlerAdapter;
    import com.luban.springmvc.init.handlerMapping.HandlerMapping;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Collection;
    import java.util.Map;
    
    public class DispatcherServlet extends HttpServlet {
        static Collection<HandlerAdapter> handlerAdapters ;
        static Collection<HandlerMapping> handlerMappings ;
    
        public DispatcherServlet() {
        }
    
        public DispatcherServlet(AnnotationConfigApplicationContext ac) {
            //组件初始化
            Map<String, HandlerMapping> handlerMappingMaps = ac.getBeansOfType(HandlerMapping.class);
            handlerMappings = handlerMappingMaps.values();
    
            Map<String, HandlerAdapter> handlerAdapterMaps = ac.getBeansOfType(HandlerAdapter.class);
            handlerAdapters = handlerAdapterMaps.values();
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
            Object handlerMapping = getHandlerMapping(req);
            if(handlerMapping == null){
                System.out.println("未匹配到handlerMapping");
                return;
            }
            HandlerAdapter handlerAdapter = getHandlerAdapter(handlerMapping);
            if(handlerAdapter == null){
                System.out.println("未匹配到handlerAdapter");
                return;
            }
            Object result = handlerAdapter.handle(req,resp,handlerMapping);
    
            PrintWriter writer = resp.getWriter();
            writer.println(result);
            writer.flush();
            writer.close();
        }
    
        protected Object getHandlerMapping(HttpServletRequest request) {
            if (this.handlerMappings != null) {
                for (HandlerMapping mapping : this.handlerMappings) {
                    Object handler = mapping.getHandlerMapping(request.getRequestURI());
                    if (handler != null) {
                        return handler;
                    }
                }
            }
            return null;
        }
    
        protected HandlerAdapter getHandlerAdapter(Object handlerMapping) {
            if (this.handlerAdapters != null) {
                for (HandlerAdapter adapter : this.handlerAdapters) {
                    boolean flag = adapter.supports(handlerMapping);
                    if (flag) {
                        return adapter;
                    }
                }
            }
            return null;
        }
    
    }
    
    

    4.HandlerMapping

    package com.luban.springmvc.init.handlerMapping;
    
    public interface HandlerMapping {
        Object getHandlerMapping(String requestURI);
    }
    
    package com.luban.springmvc.init.handlerMapping;
    
    import com.luban.springmvc.controller.Controller;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
    import org.springframework.stereotype.Component;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Component
    public class BeanNameHandlerMapping  implements HandlerMapping,InstantiationAwareBeanPostProcessor {
    
        public static Map<String, Controller> map = new HashMap<>();
    
        @Override
        public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
            if(beanName.startsWith("/")){
                map.put(beanName,(Controller)bean);
            }
            return true;
        }
    
        @Override
        public Object getHandlerMapping(String requestURI) {
            return map.get(requestURI);
        }
    }
    
    package com.luban.springmvc.init.handlerMapping;
    
    import com.luban.springmvc.annotation.RequestMapping;
    import com.luban.springmvc.servlet.RequestMappingInfo;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    
    @Component
    public class AnnotationHadlerMapping  implements HandlerMapping,InstantiationAwareBeanPostProcessor {
    
        public static Map<String,RequestMappingInfo> map = new HashMap<>();
    
        @Override
        //bean里面会有多个处理器
        public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
            Method[] methods = bean.getClass().getDeclaredMethods();
            for(Method method : methods){
                RequestMappingInfo requestMappingInfo = createRequestMappingInfo(method,bean);
                map.put(requestMappingInfo.getUri(),requestMappingInfo);
            }
            return true;
        }
    
        private RequestMappingInfo createRequestMappingInfo(Method method,Object bean) {
            RequestMappingInfo requestMappingInfo = new RequestMappingInfo();
            if(method.isAnnotationPresent(RequestMapping.class)){
                requestMappingInfo.setMethod(method);
                requestMappingInfo.setUri(method.getDeclaredAnnotation(RequestMapping.class).value());
                requestMappingInfo.setObj(bean);
            }
            return requestMappingInfo;
        }
    
        @Override
        public Object getHandlerMapping(String requestURI) {
            return map.get(requestURI);
        }
    }
    

    6.HandlerAdapter

    package com.luban.springmvc.init.handlerAdapter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    public interface HandlerAdapter {
        //该方法判断handler是否是跟该适配器对应的Handler
        public boolean supports(Object handler);
        //执行handler的业务方法
        public Object handle(HttpServletRequest request, HttpServletResponse response, Object handler);
    }
    
    package com.luban.springmvc.init.handlerAdapter;
    import com.alibaba.fastjson.JSON;
    import com.luban.springmvc.annotation.RequestParam;
    import com.luban.springmvc.annotation.ResponseBody;
    import com.luban.springmvc.servlet.RequestMappingInfo;
    import org.springframework.stereotype.Component;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Parameter;
    import java.util.Map;
    @Component
    public class AnnotationHandlerAdapter implements HandlerAdapter{
        @Override
        public boolean supports(Object handler) {
            //判断是否是RequestMapping子类
            return (handler instanceof RequestMappingInfo);
        }
        @Override
        //参数绑定
        public Object handle(HttpServletRequest request, HttpServletResponse response, Object handler){
            RequestMappingInfo requestMappingInfo = (RequestMappingInfo)handler;
            Map<String, String[]> paramMap = request.getParameterMap();//请求携带的参数
            Method method = requestMappingInfo.getMethod();//方法定义的参数
            Parameter[] parameters = method.getParameters();
    
            Object[] params = new Object[method.getParameterTypes().length];
            for(int i=0; i<parameters.length; i++){
                for(Map.Entry<String, String[]> entry : paramMap.entrySet()){
                    if(parameters[i].getAnnotation(RequestParam.class) != null && entry.getKey()!= null &&
                            entry.getKey().equals(parameters[i].getAnnotation(RequestParam.class).value())){
                        params[i] = entry.getValue()[0];
                    //jdk1.8实现反射获取方法名   1.8之前使用asm实现
                    }else if(entry.getKey().equals(parameters[i].getName())){
                        params[i] = entry.getValue()[0];
                    }
                }
    
                //传入request和response
                if(ServletRequest.class.isAssignableFrom(parameters[i].getType())){
                    params[i] = request;
                }else if(ServletResponse.class.isAssignableFrom(parameters[i].getType())){
                    params[i] = response;
                }
            }
    
            try {
                Object result = method.invoke(requestMappingInfo.getObj(),params);
                if (result instanceof String) {
                    if ("forward".equals(((String) result).split(":")[0])) {
                        request.getRequestDispatcher(((String) result).split(":")[1]).forward(request, response);
                    } else {
                        response.sendRedirect(((String) result).split(":")[1]);
                    }
                }else{
                    if(method.isAnnotationPresent(ResponseBody.class)){
                        return JSON.toJSONString(result);
                    }
                }
    
                return result;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    
    package com.luban.springmvc.init.handlerAdapter;
    
    import com.luban.springmvc.controller.Controller;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @Component
    public class BeanNameHandlerAdapter implements HandlerAdapter{
        @Override
    //    //判断hanlde是否适配当前适配器
        public boolean supports(Object handler) {
            //判断是否是RequestMapping子类
            return (handler instanceof Controller);
        }
    
        @Override
        public Object handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            return ((Controller)handler).handler(request, response);
        }
    }
    
    

    7.RequestMappingInfo

    package com.luban.springmvc.servlet;
    
    import java.lang.reflect.Method;
    
    public class RequestMappingInfo {
    
        private Method method;
    
        private String uri;
    
        private Object obj;
    
        public Object getObj() {
            return obj;
        }
    
        public void setObj(Object obj) {
            this.obj = obj;
        }
    
        public Method getMethod() {
            return method;
        }
    
        public void setMethod(Method method) {
            this.method = method;
        }
    
        public String getUri() {
            return uri;
        }
    
        public void setUri(String uri) {
            this.uri = uri;
        }
    }
    
    

    7.Controller接口

    package com.luban.springmvc.controller;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    public interface Controller {
        Object handler(HttpServletRequest request, HttpServletResponse response);
    }
    

    8.springMVC的controller类

    public class HelloController {
        @Autowired
        HelloService service;
        @RequestMapping("/test.do")
        public String test(HttpServletRequest request, HttpServletResponse response,
                         @RequestParam("param") String param){
            System.out.println("param:"+param);
            service.test(param);
            request.setAttribute("param",param);
            return "forward:/test.jsp";
        }
    
        @RequestMapping("/test1.do")
        @ResponseBody
        public Map test1(String param){
            Map map = new HashMap();
            map.put("param",param);
            return map;
        }
        @RequestMapping("/test2.do")
        @ResponseBody
        public User test2(String param){
            User user = new User();
            user.setName(param);
            user.setAge(param);
            return user;
        }
    }
    
    @Component("/testController")//通过id定义url
    public class TestController implements Controller{
        @Override
        public Object handler(HttpServletRequest request, HttpServletResponse response) {
            System.out.println("TestController");
            return null;
        }
    }
    

    相关文章

      网友评论

          本文标题:2.spring面试解答

          本文链接:https://www.haomeiwen.com/subject/bkuqwktx.html