Spring常見概念

1.Spring是什么,它的作用是什么?

Spring是一個(gè)IOC(DI)和AOP的輕量級(jí)容器框架读串,它集成了很多模塊裕寨,比如Web、AOP疚察、測(cè)試和一些基本的工具蒸走,而且Spring可以很方便的集成其他框架,比如Mybatis貌嫡、Hibernate等等比驻。它簡(jiǎn)化了java開發(fā),實(shí)現(xiàn)了代碼的解耦岛抄。IOC是控制反轉(zhuǎn)别惦,DI是依賴注入,就是將對(duì)象的創(chuàng)建夫椭、初始化掸掸、銷毀以及對(duì)象之間的依賴交給Spring來管理。AOP是面向切面編程蹭秋,我們可以通過XML配置或者注解的方式在方法執(zhí)行前扰付、執(zhí)行后、拋出異常后添加一些相應(yīng)的業(yè)務(wù)邏輯感凤,AOP經(jīng)常用來做事務(wù)悯周、日志、安全等相關(guān)功能陪竿。Spring主要是為了解決以前開發(fā)中的一些問題禽翼,從而提高開發(fā)效率屠橄,代碼解耦。

Spring為了降低Java開發(fā)的復(fù)雜性闰挡,采用了以下四種策略:

  • 基于POJO的輕量級(jí)和最小侵入性編程锐墙。不需要強(qiáng)迫實(shí)現(xiàn)Spring規(guī)范的接口和類從而對(duì)代碼和框架造成強(qiáng)耦合,最壞的情況是长酗,即使一個(gè)類使用了Spring注解溪北,但它仍然是POJO(Plain old java object 簡(jiǎn)單java對(duì)象)
  • 通過依賴注入和面向接口實(shí)現(xiàn)松耦合。將類之間的關(guān)系通過依賴注入關(guān)聯(lián)夺脾,將對(duì)象的創(chuàng)建和管理以及對(duì)象間的依賴交給Spring容器維護(hù)之拨,每個(gè)實(shí)例只需要負(fù)責(zé)執(zhí)行,執(zhí)行內(nèi)容由Spring決定
  • 基于切面和管理進(jìn)行聲明式編程咧叭。應(yīng)用切面實(shí)現(xiàn)代碼復(fù)用(模板+骨架蚀乔,骨架上有卡槽,木塊可以插入骨架的卡槽中菲茬,實(shí)現(xiàn)代碼復(fù)用)吉挣,減少不必要功能對(duì)主邏輯的侵入和代碼污染。
  • 通過切面和模板減少樣板式代碼婉弹。將樣板式代碼進(jìn)行封裝(比如JDBC本身存在大量樣板式代碼)睬魂,只需要寫核心邏輯即可镀赌。

2.什么是AOP氯哮?

答:AOP是面向切面編程,在不改變?cè)瓉矸椒I(yè)務(wù)邏輯的基礎(chǔ)上通過XML配置或者注解的方式給方法添加前置通知佩脊、后置通知蛙粘、異常通知、最終通知威彰、環(huán)繞通知出牧,從而將很多業(yè)務(wù)方法都要用到的業(yè)務(wù)邏輯或功能添加到切點(diǎn)。我們通常用AOP做日志歇盼、事務(wù)舔痕、權(quán)限等功能。

3.AOP的XML配置實(shí)現(xiàn)方式和注解實(shí)現(xiàn)方式豹缀?

使用XML的配置方式實(shí)現(xiàn)AOP

首先需要一個(gè)增強(qiáng)類伯复,這個(gè)類根據(jù)通知的類型去實(shí)現(xiàn)如MethodBeforeAdvice、AfterReturningAdvice 的接口邢笙,然后復(fù)寫相應(yīng)方法啸如。再在XML中配置需要增強(qiáng)的方法的類的bean,增強(qiáng)類的bean氮惯,然后配置切點(diǎn)叮雳,也就是需要增強(qiáng)的方法想暗,再將增強(qiáng)類和切點(diǎn)關(guān)聯(lián),再配置動(dòng)態(tài)代理帘不。

注解方式的實(shí)現(xiàn)AOP

首先導(dǎo)入包说莫,然后使用@aspect配置切面類,使用@pointcut定義切點(diǎn)寞焙,@before等定義通知储狭,最后在XML中開啟注解掃描,開啟aop注解捣郊。

4.AOP的實(shí)現(xiàn)原理辽狈?

AOP底層實(shí)現(xiàn)原理是代理設(shè)計(jì)模式。代理模式是通過代理控制對(duì)象的訪問呛牲,可以詳細(xì)訪問某個(gè)對(duì)象的方法稻艰,在這方法調(diào)用前后處理。

代理分類分為靜態(tài)代理和動(dòng)態(tài)代理侈净。

5.什么是靜態(tài)代理?什么是動(dòng)態(tài)代理僧凤?

靜態(tài)代理

靜態(tài)代理是指在代碼運(yùn)行前就已經(jīng)存在代理類的字節(jié)碼文件畜侦,代理類和委托類的關(guān)系在運(yùn)行前就已經(jīng)確定了。說白了就是程序員自己編寫或者生成的代理類源碼躯保,再編譯代理類旋膳。

public interface IUserDao {
    void save();
}

public class UserDao implements IUserDao {
    public void save() {
        System.out.println("已經(jīng)保存數(shù)據(jù)...");
    }
}

//代理類
public class UserDaoProxy implements IUserDao {
    private IUserDao target;
    public UserDaoProxy(IUserDao iuserDao) {
        this.target = iuserDao;
    }
    public void save() {
        System.out.println("保存接口調(diào)用開始...");
        target.save();
        System.out.println("保存接口調(diào)用結(jié)束...");
        }
 }

動(dòng)態(tài)代理

動(dòng)態(tài)代理是在程序運(yùn)行時(shí)通過反射機(jī)制動(dòng)態(tài)生成字節(jié)碼文件。動(dòng)態(tài)代理分為JDK動(dòng)態(tài)代理和Cglib動(dòng)態(tài)代理途事。

JDK動(dòng)態(tài)代理
/**
 * JDK動(dòng)態(tài)代理
 * 每次生成動(dòng)態(tài)代理類對(duì)象時(shí),實(shí)現(xiàn)了InvocationHandler接口的調(diào)用處理器對(duì)象
 * <p>
 * 1.通過實(shí)現(xiàn)InvocationHandler接口創(chuàng)建自己的調(diào)用處理器 IvocationHandler handler = new InvocationHandlerImpl(…);
 * 2.通過為Proxy類指定ClassLoader對(duì)象和一組interface創(chuàng)建動(dòng)態(tài)代理類
     Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
 * 3.通過反射機(jī)制獲取動(dòng)態(tài)代理類的構(gòu)造函數(shù)验懊,其參數(shù)類型是調(diào)用處理器接口類型
     Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
 * 4.通過構(gòu)造函數(shù)創(chuàng)建代理類實(shí)例,此時(shí)需將調(diào)用處理器對(duì)象作為參數(shù)被傳入
     Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
 *
 * @author youyou
 */
public class InvocationHandlerImpl implements InvocationHandler {

/**
 * 這其實(shí)業(yè)務(wù)實(shí)現(xiàn)類對(duì)象尸变,用來調(diào)用具體的業(yè)務(wù)方法
 */
private Object target;

/**
 * 通過構(gòu)造函數(shù)傳入目標(biāo)對(duì)象
 *
 * @param target
 */
public InvocationHandlerImpl(Object target) {
    this.target = target;
}

/**
 * 代理具體功能在這里實(shí)現(xiàn)
 *
 */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object result;
    System.out.println("調(diào)用開始處理");
    result = method.invoke(target, args);
    System.out.println("調(diào)用結(jié)束處理");
    return result;
}

public static void main(String[] args) throws SecurityException, IllegalArgumentException {
    //初始化委托類义图,構(gòu)造代理類
    IUserDao userDao = new UserDao();
    InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDao);
    ClassLoader loader = userDao.getClass().getClassLoader();
    Class<?>[] interfaces = userDao.getClass().getInterfaces();
    //對(duì)Proxy指定ClassLoader和一組interface創(chuàng)建動(dòng)態(tài)代理類
    IUserDao newProxyInstance = (IUserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl);
    newProxyInstance.save();
  }
}

JDK動(dòng)態(tài)代理簡(jiǎn)單來說就是生成一個(gè)包裝類對(duì)象,由于代理對(duì)象是動(dòng)態(tài)的召烂,所以是動(dòng)態(tài)代理碱工。由于我們需要增強(qiáng),這個(gè)增強(qiáng)需要留給開發(fā)人員開發(fā)代碼的奏夫,因此代理對(duì)象不能直接包含被代理對(duì)象怕篷,而是一個(gè)InvocationHandler,該對(duì)象包含被代理對(duì)象酗昼,并負(fù)責(zé)分發(fā)請(qǐng)求給代理對(duì)象廊谓,分發(fā)前后均可增強(qiáng)。從原理上看麻削,JDK動(dòng)態(tài)代理是對(duì)“對(duì)象”的代理蒸痹。
JDK動(dòng)態(tài)代理要求被代理類必須實(shí)現(xiàn)接口(Proxy.newProxyInstance第二個(gè)參數(shù))春弥。

Cglib動(dòng)態(tài)代理
/**
 * Cglib動(dòng)態(tài)代理實(shí)現(xiàn)
 */
 public class CglibProxy implements MethodInterceptor {

/**
 * 這里的目標(biāo)類型為Object,則可以接受任意一種參數(shù)作為被代理類电抚,實(shí)現(xiàn)了動(dòng)態(tài)代理
 */
public Object getInstance(Class<?> clazz) {
    // 設(shè)置需要?jiǎng)?chuàng)建子類的類
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(clazz);
    enhancer.setCallback(this);
    return enhancer.create();
}

@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    System.out.println("開啟事物");
    Object result = proxy.invokeSuper(obj, args);
    System.out.println("關(guān)閉事物");
    // 返回代理對(duì)象
    return result;
}

public static void main(String[] args) {
      CglibProxy cglibProxy = new CglibProxy();
      UserDao userDao = (UserDao) cglibProxy.getInstance(UserDao.class);
      userDao.save();
    }
}

Cglib動(dòng)態(tài)代理只需要一個(gè)類型clazz就可以產(chǎn)生一個(gè)代理對(duì)象惕稻, 所以說是“類的代理”,且創(chuàng)造的對(duì)象通過打印類型發(fā)現(xiàn)也是一個(gè)新的類型蝙叛。

6. Spring的Bean的注入方式俺祠?

  • 屬性注入:通過setXXX( )方法注入bean的屬性值或依賴對(duì)象
  • 構(gòu)造函數(shù)注入
  • 工廠方法注入(包括非靜態(tài)工廠或靜態(tài)工廠,區(qū)別就是在創(chuàng)建Bean實(shí)例的時(shí)候需不需要?jiǎng)?chuàng)建一個(gè)工廠類實(shí)例從而調(diào)用工廠類創(chuàng)建Bean的方法)

7. Spring中Bean的生命周期

Spring中bean的生命周期大致分為:實(shí)例化借帘、初始化蜘渣、運(yùn)行、銷毀

  • 通過構(gòu)造器或工廠方法創(chuàng)建bean的實(shí)例肺然,此時(shí)會(huì)加載類蔫缸,執(zhí)行類加載的加載、驗(yàn)證际起、準(zhǔn)備拾碌、解析、初始化這幾個(gè)步驟
  • 為bean的屬性設(shè)置值街望,并注入對(duì)其他bean的引用
  • 調(diào)用bean的初始化方法
  • 運(yùn)行:初始化完成后bean就可以使用了
  • 銷毀:當(dāng)容器關(guān)閉校翔,調(diào)用bean的銷毀方法

8. Spring中的常用注解?

  • @Controller:指明該類是一個(gè)controller
  • @Service:指明該類是一個(gè)service
  • @Repository:指明該類是一個(gè)dao
  • @Componet:指明這是一個(gè)組件類灾前,交給Spring管理
  • @RequestMapping:申明類或方法匹配的URL
  • @Autowired:通過反射自動(dòng)裝配

9. 過濾器和攔截器的區(qū)別

過濾器

過濾器依賴Servlet容器防症,只能在容器初始化時(shí)調(diào)用一次,基于回調(diào)函數(shù)可以對(duì)幾乎所有請(qǐng)求進(jìn)行過濾哎甲。
應(yīng)用場(chǎng)景:可以用來統(tǒng)一字符編碼集蔫敲、過濾敏感字符、訪問權(quán)限控制炭玫。
實(shí)現(xiàn)方式:寫一個(gè)過濾器類實(shí)現(xiàn)filter接口奈嘿,復(fù)寫init、dofilter吞加、destory方法指么。

攔截器

攔截器依賴于Web框架,如果是使用SpringMVC就是依賴于SpringMVC框架榴鼎〔埽基于Java的反射機(jī)制,屬于AOP的一種應(yīng)用巫财,由于攔截器基于Web框架盗似,所以可以使用Spring的依賴注入進(jìn)行業(yè)務(wù)操作∑较睿可以在controller生命周期之內(nèi)多次調(diào)用赫舒。但是缺點(diǎn)是只能對(duì)controller請(qǐng)求進(jìn)行攔截悍及,對(duì)其他的一些比如直接訪問靜態(tài)資源的請(qǐng)求則沒辦法進(jìn)行攔截處理。
實(shí)現(xiàn)方式:實(shí)現(xiàn)HandlerInterceptor接口接癌,并復(fù)寫preHandle心赶、postHandle、afterCompletion方法缺猛。

區(qū)別

  • 過濾器基于函數(shù)回調(diào)缨叫,攔截器基于反射
  • 過濾器依賴于Servlet容器,攔截器依賴于Web框架
  • 過濾器幾乎對(duì)所有請(qǐng)求起作用荔燎,攔截器只對(duì)action請(qǐng)求起作用
  • 過濾器只能在容器初始化的時(shí)候被調(diào)用一次耻姥,攔截器可以在action的生命周期中被調(diào)用多次
  • 攔截器可以獲取IOC容器中的各個(gè)bean,而過濾器就不行有咨,這點(diǎn)很重要琐簇,在攔截器里注入一個(gè)service,可以調(diào)用業(yè)務(wù)邏輯座享。

執(zhí)行順序

執(zhí)行順序.png

10. Spring中Bean的常用作用域

  • Singleton(單例):使用此作用域的Bean在Spring容器中只有一個(gè)實(shí)例婉商,即無論多少個(gè)Bean引用它都指向同一個(gè)對(duì)象。(默認(rèn)作用域)
  • Prototype(原型):每次通過Spring容器獲取Bean(注入或者通過應(yīng)用上下文獲取)的時(shí)候都會(huì)創(chuàng)建一個(gè)新的Bean實(shí)例渣叛。
  • Session(會(huì)話):在Web應(yīng)用中据某,為每個(gè)回話創(chuàng)建一個(gè)bean實(shí)例(購物車)。
  • Request(請(qǐng)求):在Web應(yīng)用中诗箍,為每個(gè)請(qǐng)求創(chuàng)建一個(gè)bean實(shí)例。
  • global-session:全局會(huì)話挽唉,所有會(huì)話共享一個(gè)實(shí)例滤祖。

11. Spring中的核心對(duì)象

BeanFactory

BeanFactory產(chǎn)生一個(gè)新的實(shí)例,可以實(shí)現(xiàn)單例模式瓶籽,是Spring用來實(shí)例化匠童、配置和管理Bean的。它使用的是懶加載塑顺,如果某個(gè)Bean中的某個(gè)屬性沒有注入汤求,使用BeanFactory加載后要在第一次調(diào)用getBean方法才會(huì)拋出異常。

BeanWrapper

提供統(tǒng)一的get及set方法

ApplicationContext

ApplicationContext提供框架的實(shí)現(xiàn)严拒,是BeanFactory的實(shí)現(xiàn)類扬绪,是對(duì)它功能的一個(gè)拓展,ApplicationContext使用的是迫切加載裤唠,這個(gè)類會(huì)自動(dòng)解析我們配置的applicationContext.xml挤牛,然后根據(jù)我們配置的bean來new對(duì)象,將new好的對(duì)象放進(jìn)一個(gè)Map中种蘸,鍵就是我們bean的id,值就是new的對(duì)象墓赴。

12. Spring FactoryBean和BeanFactory 區(qū)別

BeanFactory是個(gè)bean 工廠竞膳,是一個(gè)工廠類(接口), 它負(fù)責(zé)生產(chǎn)和管理bean的一個(gè)工廠是ioc 容器最底層的接口诫硕,是個(gè)ioc容器坦辟,是spring用來管理和裝配普通bean的ioc容器(這些bean成為普通bean)。
FactoryBean是個(gè)bean章办,在IOC容器的基礎(chǔ)上給Bean的實(shí)現(xiàn)加上了一個(gè)簡(jiǎn)單工廠模式和裝飾模式锉走,是一個(gè)可以生產(chǎn)對(duì)象和裝飾對(duì)象的工廠bean,由spring管理后纲菌,生產(chǎn)的對(duì)象是由getObject()方法決定的(從容器中獲取到的對(duì)象不是“ FactoryBeanTest ” 對(duì)象)挠日。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市翰舌,隨后出現(xiàn)的幾起案子嚣潜,更是在濱河造成了極大的恐慌,老刑警劉巖椅贱,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懂算,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡庇麦,警方通過查閱死者的電腦和手機(jī)计技,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來山橄,“玉大人垮媒,你說我怎么就攤上這事『嚼猓” “怎么了睡雇?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長饮醇。 經(jīng)常有香客問我它抱,道長,這世上最難降的妖魔是什么朴艰? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任观蓄,我火速辦了婚禮,結(jié)果婚禮上祠墅,老公的妹妹穿的比我還像新娘侮穿。我一直安慰自己,他們只是感情好毁嗦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布撮珠。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芯急。 梳的紋絲不亂的頭發(fā)上勺届,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音娶耍,去河邊找鬼免姿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛榕酒,可吹牛的內(nèi)容都是我干的胚膊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼想鹰,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼紊婉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辑舷,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤喻犁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后何缓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肢础,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年碌廓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了传轰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谷婆,死狀恐怖慨蛙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情纪挎,我是刑警寧澤期贫,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站廷区,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏贾铝。R本人自食惡果不足惜隙轻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望垢揩。 院中可真熱鬧玖绿,春花似錦、人聲如沸叁巨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锋勺。三九已至蚀瘸,卻和暖如春狡蝶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贮勃。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國打工贪惹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寂嘉。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓奏瞬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親泉孩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子硼端,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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

  • 如下是整篇文章的結(jié)構(gòu),所需閱讀時(shí)間大約20min Spring簡(jiǎn)介 Spring框架由Rod Johnson開發(fā)寓搬,...
    李序鍇閱讀 893評(píng)論 0 15
  • Spring框架是由于軟件開發(fā)的復(fù)雜性而創(chuàng)建的珍昨。Spring使用的是基本的JavaBean來完成以前只可能由EJB...
    OSET我要編程閱讀 2,706評(píng)論 0 3
  • Spring框架官網(wǎng)下載教程:https://blog.csdn.net/saszyl/article/detai...
    惜小八閱讀 591評(píng)論 0 1
  • 做生意的,要獲取足夠的客流订咸,可以從兩方面入手曼尊。 一方面可以讓客戶單次盡量久的留在店內(nèi)。 顧客呆在店里的時(shí)間越長脏嚷,發(fā)...
    蘇說閱讀 726評(píng)論 0 0
  • 有人說“家人在哪骆撇,家就在哪”,我很同意這個(gè)觀點(diǎn)父叙,以至于有很久很久沒有回到出生地的老家了神郊。只記得兒時(shí)的時(shí)候,家里...
    AngellaLiu閱讀 166評(píng)論 0 1