2.spring面试解答

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;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容