2.spring面試解答

SpringIOC

1.解析配置類Config.class思灰,獲取配置類上面@componetScan注解的值package

2.掃描package下的類雾袱,并把帶有@Compent注解的以及繼承自@Compent注解的類萧锉,解析成
beanDefintion(bean定義),解析類中定義的@Scope @Lazy 等注解設(shè)置為定義的屬性,解析完成
放入容器中beanDefintionMap中

3.實(shí)例化非懶加載的單例bean
3.1對(duì)beanDefintionMap中的bean定義進(jìn)行合并昼汗,放入合并后的bean定義容器中mergedBeanDefinitionMap
3.2.循環(huán)遍歷合并后的bean定義容器献宫,
根據(jù)bean定義中的scope屬性查看是否是單例的bean愿待,并查看是否是懶加載观谦,實(shí)例化單例非懶加載的bean
實(shí)例化之后進(jìn)行屬性填充拉盾,
屬性填充之后判斷bean是否實(shí)現(xiàn)了Aware接口,調(diào)用Aware接口的實(shí)現(xiàn)方法
然后調(diào)用bean的初始化方法進(jìn)行初始化
如果有切面豁状,需要進(jìn)行動(dòng)態(tài)代理捉偏,生成代理bean
把生成的bean放入單例池倒得。bean的實(shí)例化過(guò)程在spring中是調(diào)用bean的不同的后置處理器來(lái)完成的。

Spring AOP

切面(創(chuàng)建一個(gè)切面類@Aspect,切面類里面定義了很多切點(diǎn))
切點(diǎn):@PointCut(com.methd*) 連接點(diǎn)的集合
連接點(diǎn) 就是需要切入的某個(gè)方法
通知 切入的時(shí)機(jī)+切入的邏輯夭禽。@Before("myPointCut")

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

單例作用域的bean中引入原型作用域的Bean的問(wèn)題

單例作用域的bean中引入原型作用域的Bean的問(wèn)題
如果一個(gè)單例的bean中引用了一個(gè)多例的bean霞掺,這時(shí)候這個(gè)多例的bean只會(huì)被注入一次,所以達(dá)不到多例的效果了驻粟,如果想要達(dá)到多例的效果可以如下作用:

@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() {
        // 這樣每次調(diào)用就可以創(chuàng)建一個(gè)新的實(shí)例,
        //但是這種做法 代碼侵入性太高
        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.  請(qǐng)求進(jìn)來(lái)之后會(huì)進(jìn)入到doDispatch()方法中根悼。
2.  根據(jù)request從handlermappings循環(huán)獲取handler,并構(gòu)建成一個(gè)調(diào)用鏈對(duì)象
       HandlerExecutionChain,調(diào)用鏈中包含handler對(duì)象以及攔截器蜀撑。
      注意:springMVC中生命一個(gè)controller有三種方式:@Controller注解\實(shí)現(xiàn)
      Controller接口\實(shí)現(xiàn)HttpRequestHandler接口分別對(duì)應(yīng)三種映射器來(lái)獲取
      handler對(duì)象挤巡。這三種方式@Contoller是把對(duì)象中的方法解析成一個(gè)個(gè)handler;
      其余兩種其實(shí)就是從Spring容器中獲取真實(shí)的對(duì)象酷麦。
3.  根據(jù)request從匹配出適合的適配器矿卑,適配器也有三種分別對(duì)應(yīng)不同的Controller類型,
4.  Chain.applyPreHandle()按順序調(diào)用攔截器
5.  Ha.hand(hand) –通過(guò)適配器調(diào)用handle對(duì)應(yīng)的方法。其中@Controller類型是通過(guò)反射調(diào)用沃饶,
   期間會(huì)通過(guò)策略模式母廷,根據(jù)不同類型的參數(shù)調(diào)用不同的參數(shù)解析器從request中解析參 
   數(shù)值,然后通過(guò)反射調(diào)用controller的方法;根據(jù)方法的返回值以及方法上有沒(méi)有加@ResponseBody注解糊肤,
   來(lái)判斷是走視圖解析器還是走消息轉(zhuǎn)換器琴昆。
6.  Chain.applyPostHandle()調(diào)用攔截器
7.  調(diào)用視圖解析器渲染參數(shù)以及頁(yè)面跳轉(zhuǎn)。

手寫springMVC

1.tomcat啟動(dòng)類

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規(guī)范利用SPI機(jī)制web容器啟動(dòng)完畢之后加載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里面會(huì)有多個(gè)處理器
    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是否是跟該適配器對(duì)應(yīng)的Handler
    public boolean supports(Object handler);
    //執(zhí)行handler的業(yè)務(wù)方法
    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
    //參數(shù)綁定
    public Object handle(HttpServletRequest request, HttpServletResponse response, Object handler){
        RequestMappingInfo requestMappingInfo = (RequestMappingInfo)handler;
        Map<String, String[]> paramMap = request.getParameterMap();//請(qǐng)求攜帶的參數(shù)
        Method method = requestMappingInfo.getMethod();//方法定義的參數(shù)
        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實(shí)現(xiàn)反射獲取方法名   1.8之前使用asm實(shí)現(xiàn)
                }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是否適配當(dāng)前適配器
    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")//通過(guò)id定義url
public class TestController implements Controller{
    @Override
    public Object handler(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("TestController");
        return null;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末馆揉,一起剝皮案震驚了整個(gè)濱河市业舍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌升酣,老刑警劉巖舷暮,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異噩茄,居然都是意外死亡下面,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門绩聘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)沥割,“玉大人,你說(shuō)我怎么就攤上這事君纫⊙庇觯” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵蓄髓,是天一觀的道長(zhǎng)叉庐。 經(jīng)常有香客問(wèn)我,道長(zhǎng)会喝,這世上最難降的妖魔是什么陡叠? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任玩郊,我火速辦了婚禮,結(jié)果婚禮上枉阵,老公的妹妹穿的比我還像新娘译红。我一直安慰自己,他們只是感情好兴溜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布侦厚。 她就那樣靜靜地躺著,像睡著了一般拙徽。 火紅的嫁衣襯著肌膚如雪刨沦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天膘怕,我揣著相機(jī)與錄音想诅,去河邊找鬼。 笑死岛心,一個(gè)胖子當(dāng)著我的面吹牛来破,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忘古,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼徘禁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了髓堪?” 一聲冷哼從身側(cè)響起晌坤,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旦袋,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體它改,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疤孕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了央拖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祭阀。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鲜戒,靈堂內(nèi)的尸體忽然破棺而出专控,到底是詐尸還是另有隱情,我是刑警寧澤遏餐,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布伦腐,位于F島的核電站,受9級(jí)特大地震影響失都,放射性物質(zhì)發(fā)生泄漏柏蘑。R本人自食惡果不足惜幸冻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望咳焚。 院中可真熱鬧洽损,春花似錦、人聲如沸革半。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)又官。三九已至延刘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赏胚,已是汗流浹背访娶。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留觉阅,地道東北人崖疤。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像典勇,于是被迫代替她去往敵國(guó)和親劫哼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容