Spring入門

說明:本文主要內(nèi)容來自慕課網(wǎng)。配合視頻食用口味更佳虾攻。
主要是順著已經(jīng)學(xué)習(xí)的視頻順序總結(jié)一遍帽借,以深化理解和方便日后復(fù)習(xí)憔维。
本部分只包含IOC和AOP。

第一章 概述

Spring 入門課程簡介

本門課程包含的內(nèi)容:
Spring簡介
IOC(配置谋减、注解)
Bean(配置、注解)
AOP(配置、注解难裆、AspetJ、API)

Spring概況

Spring是什么

  • Spring是一個開源框架镊掖,最初為了解決企業(yè)應(yīng)用開發(fā)的復(fù)雜性而創(chuàng)建的乃戈,但現(xiàn)在已經(jīng)不止應(yīng)用于企業(yè)應(yīng)用
  • 是一個輕量級的控制反轉(zhuǎn)(IOC)和面向切面(AOP)的容器框架
    • 大小與開銷兩方面而言Spring都是輕量的
    • 通過控制反轉(zhuǎn)(IOC)的技術(shù)達(dá)到松耦合的目的
    • 提供了面向切面編程(AOP)的豐富支持,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級服務(wù)進(jìn)行內(nèi)聚性的開發(fā)
    • 包含并管理應(yīng)用對象的配置和生命周期堰乔,這個意義上是一種容器偏化。
    • 將簡單的組件配置、組合成為復(fù)雜的應(yīng)用镐侯,這個意義上是框架

為什么是Spring

  • 在Spring上開發(fā)應(yīng)用簡單
  • 在Spring上開發(fā)應(yīng)用方便
  • 在Spring上開發(fā)應(yīng)用快捷

Spring作用

  • 容器
  • 提供了多種技術(shù)的支持
    --JMS
    --MQ支持
    --UnitTest
  • AOP(事務(wù)管理侦讨、日志等)
  • 提供了眾多方便應(yīng)用的輔助類(JDBC Template等)
  • 對主流應(yīng)用框架(Hibernate等)提供了良好的支持

適用范圍

  • 構(gòu)建企業(yè)應(yīng)用(SpringMVC+Spring+Hibernate/MyBatis)
  • 單獨(dú)使用Bean容器(Bean管理)
  • 單獨(dú)使用AOP進(jìn)行切面處理
  • 其他的Spring功能:如:對消息的支持等
  • 在互聯(lián)網(wǎng)中的應(yīng)用

Spring框架

Spring框架總覽

框架

什么是框架

維基百科:軟件框架,通常是指為了實(shí)現(xiàn)某個業(yè)界標(biāo)準(zhǔn)或者完成特定基本任務(wù)的軟件組件規(guī)范苟翻,也指為了實(shí)現(xiàn)某個軟件組織規(guī)范時韵卤,提供規(guī)范所要求之基礎(chǔ)功能的軟件產(chǎn)品。

通俗的說崇猫,框架就是制定一套規(guī)范或者規(guī)則(思想)沈条,大家(程序員)在該規(guī)范或者規(guī)程(思想)下工作。用現(xiàn)實(shí)生活中的比喻就是:使用別人搭好的舞臺诅炉,你來做表演蜡歹。

框架的特點(diǎn)

  • 半成品
  • 封裝了特定的處理流程和控制邏輯
  • 成熟的屋厘、不斷升級的軟件

框架與類庫的區(qū)別

  • 框架一般是封裝了邏輯、高內(nèi)聚的月而,類庫則是松散的工具組合汗洒。
  • 框架專注于某一領(lǐng)域,類庫則是更通用的父款。
框架于類庫區(qū)別
  • 類庫通過不同的方式組裝成不同的框架

為什么使用框架

  • 軟件系統(tǒng)日趨復(fù)雜
  • 重用度高溢谤,開發(fā)效率和質(zhì)量提高
  • 軟件設(shè)計(jì)人員要專注于對領(lǐng)域的了解,使需求分析更充分
  • 易于上手憨攒、快速解決問題

第二章 Spring IOC 容器

接口與面向接口編程

接口

  • 用于溝通的中介物的抽象化
  • 實(shí)體把自己提供給外界的一種抽象化說明世杀,用以由內(nèi)部操作分離出外部溝通方式,使其能被修改內(nèi)部而不影響外界其他實(shí)體與其交互的方式肝集。
  • 對應(yīng)Java接口即聲明瞻坝,聲明了哪些方法對外提供的。
  • 在Java8中包晰,接口可以擁有方法體

面向接口編程

  • 結(jié)構(gòu)設(shè)計(jì)中湿镀,分清層次及調(diào)用關(guān)系,每層只向外(上層)提供一組功能接口伐憾,各層間僅依賴接口而非實(shí)現(xiàn)類
  • 接口實(shí)現(xiàn)的變動不影響各層間的調(diào)用勉痴,這一點(diǎn)在公共服務(wù)中尤為重要
  • “面向接口編程”中的“接口”是用于隱藏具體實(shí)現(xiàn)和實(shí)現(xiàn)多態(tài)性的組件

什么是IOC

站在過程的角度看

IOC:控制反轉(zhuǎn),控制權(quán)的轉(zhuǎn)移树肃,不再是應(yīng)用程序本身-->依賴對象的創(chuàng)建和維護(hù)蒸矛,而是由外部容器-->依賴對象的創(chuàng)建和維護(hù)

站在主體的角度看

DI(依賴注入)是其中一種實(shí)現(xiàn)方式
2004年,Martin Fowler探討了同一個問題胸嘴,既然IoC是控制反轉(zhuǎn)雏掠,那么 到底是“哪些方面被控制反轉(zhuǎn)了呢?”劣像,經(jīng)過詳細(xì)的分析和論證后乡话,他得出了答案:“獲得依賴對象的過程被反轉(zhuǎn)了”《龋控制被反轉(zhuǎn)之后绑青,獲得依賴對象的過程由自身管理變成了由IOC容器的主動注入。于是屋群,他給“控制反轉(zhuǎn)” 取了一個更合適的名字“依賴注入(Dependency Injection)”闸婴。他的這個答案,實(shí)際上給出了實(shí)現(xiàn)IoC的方法:注入芍躏。
所謂依賴注入邪乍,就是由IoC容器 在運(yùn)行期間,動態(tài)地將某種依賴關(guān)系注入到對象之中。

目的

創(chuàng)建對象并且組裝對象之間的關(guān)系

IOC簡單類比

通過中介找房子 通過IOC使用對象
找中介 找IOC容器
中介介紹房子 容器返回對象
租房庇楞、入住 使用對象

Spring的Bean配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd" >
     
    //這是我們要配置的內(nèi)容
    <bean id="oneInterface" class="com.imooc.ioc.interfaces.OneInterfaceImpl"></bean>

 </beans>

Java bean是什么

Bean容器初始化

基礎(chǔ)

兩個包:

  • org.springframework.beans
  • org.springframework.context

容器:

  • BeanFactory提供配置結(jié)構(gòu)和基本功能榜配,加載并初始化Bean
  • ApplicationContext保存了Bean對象,并在Spring中廣泛使用

BeanFactory和ApplicationContext是Spring兩種很重要的容器,前者提供了最基本的依賴注入的支持姐刁,而后者在繼承前者的基礎(chǔ)進(jìn)行了功能的拓展芥牌,例如增加了事件傳播,資源訪問和國際化的消息訪問等功能聂使。

方式---ApplicationContext

1. 本地文件

FileSystemXmlApplicationContext

FileSystemXmlApplicationContext context = new 
FileSystemXmlApplicationContext("F:/workspace/appcontext.xml");

2. 類路徑

ClassPathXmlApplicationContext

ClassPathXmlApplicationContext context = new
ClassPathXmlApplicationContext("classpath:spring-context.xml");

3. Web應(yīng)用

依賴servletListener

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderServlet</listener-class>
</listener>
<servlet>
    <servlet-name>context</servlet-name>
    <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
    <load-on-startup>on</load-on-startup>
</servlet>

Spring注入方式

Spring注入是指在啟動Spring容器加載bean配置的時候,完成對變量的賦值行為谬俄。常用的兩種注入方式設(shè)值注入構(gòu)造注入柏靶。

設(shè)值注入---property

通過setter注入。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd" >

      <bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">
            <property name="injectionDAO" ref="injectionDAO"></property>
      </bean>


      <bean id="injectionDAO" class="com.imooc.ioc.injection.dao.InjectionDAOImpl"></bean>

 </beans>

構(gòu)造注入---constructor-arg

通過構(gòu)造器注入溃论。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd" >


        <bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">
            <constructor-arg name="injectionDAO" ref="injectionDAO"></constructor-arg>
        </bean>

        <bean id="injectionDAO" class="com.imooc.ioc.injection.dao.InjectionDAOImpl"></bean>

 </beans>

第三章:Spring Bean裝配(上)

Bean的配置項(xiàng)及作用域

Bean配置項(xiàng)

屬性 描述
id|name 這個屬性指定唯一的 bean 標(biāo)識符屎蜓。在基于 XML 的配置元數(shù)據(jù)中,可以使用 id 或 name 屬性來指定 bean 標(biāo)識符
class 這個屬性是強(qiáng)制性的钥勋,并且指定用來創(chuàng)建 bean 的bean 類
scope 這個屬性指定由特定的 bean 定義創(chuàng)建的對象的作用域
constructor-arg 用來注入依賴關(guān)系
properties 用來注入依賴關(guān)系
autowiring mode 用來注入依賴關(guān)系
lazy-initialization mode 延遲初始化的 bean 告訴 IoC 容器在它第一次被請求時炬转,而不是在啟動時去創(chuàng)建一個 bean 實(shí)例
initialization() 在 bean 的所有必需的屬性被容器設(shè)置之后,調(diào)用回調(diào)方法
destruction() 當(dāng)包含該 bean 的容器被銷毀時算灸,使用回調(diào)方法

Bean的作用域

添加方式

<bean id=" " class=" " scope="singleton"></bean>
作用域 描述
singleton 單例扼劈,指一個Bean容器中只存在一份
prototype 每次請求(每次使用)創(chuàng)建新的實(shí)例,destroy方式不生效
request 每次http請求創(chuàng)建一個實(shí)例且僅在當(dāng)前request內(nèi)有效
session 同上菲驴,每次http請求創(chuàng)建荐吵,當(dāng)前session內(nèi)有效
global session 基于portlet的web中有效(portlet定義了global session),如果在web中赊瞬,同session

Bean的生命周期

Bean的生命周期
  1. 首先容器啟動后先煎,會對scope為singleton且非懶加載的bean進(jìn)行實(shí)例化
  2. 按照Bean定義信息配置信息,注入所有的屬性
  3. 如果Bean實(shí)現(xiàn)了BeanNameAware接口巧涧,會回調(diào)該接口的setBeanName()方法薯蝎,傳入該Bean的id,此時該Bean就獲得了自己在配置文件中的id
  4. 如果Bean實(shí)現(xiàn)了BeanFactoryAware接口,會回調(diào)該接口的setBeanFactory()方法谤绳,傳入該Bean的BeanFactory占锯,這樣該Bean就獲得了自己所在的BeanFactory
  5. 如果Bean實(shí)現(xiàn)了ApplicationContextAware接口,會回調(diào)該接口的setApplicationContext()方法,傳入該Bean的ApplicationContext闷供,這樣該Bean就獲得了自己所在的ApplicationContext烟央,
  6. 如果有Bean實(shí)現(xiàn)了BeanPostProcessor接口,則會回調(diào)該接口的postProcessBeforeInitialzation()方法
  7. 如果Bean實(shí)現(xiàn)了InitializingBean接口歪脏,則會回調(diào)該接口的afterPropertiesSet()方法
  8. 如果Bean配置了init-method方法疑俭,則會執(zhí)行init-method配置的方法
  9. 如果有Bean實(shí)現(xiàn)了BeanPostProcessor接口,則會回調(diào)該接口的postProcessAfterInitialization()方法
    10.經(jīng)過流程9之后婿失,就可以正式使用該Bean了,對于scope為singleton的Bean,Spring的ioc容器中會緩存一份該bean的實(shí)例钞艇,而對于scope為prototype的Bean,每次被調(diào)用都會new一個新的對象啄寡,期生命周期就交給調(diào)用方管理了,不再是Spring容器進(jìn)行管理了
    11.容器關(guān)閉后哩照,如果Bean實(shí)現(xiàn)了DisposableBean接口挺物,則會回調(diào)該接口的destroy()方法
    12.如果Bean配置了destroy-method方法,則會執(zhí)行destroy-method配置的方法

至此飘弧,整個Bean的生命周期結(jié)束

創(chuàng)建與銷毀

方法1:實(shí)現(xiàn)InitializingBean和DisposableBean接口

這兩個接口都只包含一個方法识藤。

  • 實(shí)現(xiàn)InitializingBean接口的afterPropertiesSet()方法可以在Bean屬性值設(shè)置好之后做一些操作
  • 實(shí)現(xiàn)DisposableBean接口的destroy()方法可以在銷毀Bean之前做一些操作。

如下:

public class GiraffeService implements InitializingBean,DisposableBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("執(zhí)行InitializingBean接口的afterPropertiesSet方法");
    }
 
    @Override
    public void destroy() throws Exception {
        System.out.println("執(zhí)行DisposableBean接口的destroy方法");
    }
}

這種方法比較簡單次伶,但是不建議使用痴昧。因?yàn)檫@樣會將Bean的實(shí)現(xiàn)和Spring框架耦合在一起。

方法2:在bean的配置文件中指定init-method和destroy-method方法

Spring允許我們創(chuàng)建自己的init方法和destroy方法冠王,只要在Bean的配置文件中指定init-methoddestroy-method的值就可以在Bean初始化時和銷毀之前執(zhí)行一些操作赶撰。

配置文件中的配置:

<bean name="giraffeService" class="com.giraffe.spring.service.GiraffeService" 
                            init-method="initMethod" destroy-method="destroyMethod">
</bean>

代碼:

public class GiraffeService {
    //通過<bean>的destroy-method屬性指定的銷毀方法
    public void destroyMethod() throws Exception {
        System.out.println("執(zhí)行配置的destroy-method");
    }
 
    //通過<bean>的init-method屬性指定的初始化方法
    public void initMethod() throws Exception {
        System.out.println("執(zhí)行配置的init-method");
    }
}

需要注意的是自定義的init-method和post-method方法可以拋異常但是不能有參數(shù)。
這種方式比較推薦柱彻,因?yàn)榭梢宰约簞?chuàng)建方法豪娜,無需將Bean的實(shí)現(xiàn)直接依賴于spring的框架

方法3:使用@PostConstruct和@PreDestroy注解

  • 除了xml配置的方式哟楷,Spring也支持用@PostConstruct@PreDestroy注解來指定init和destroy方法瘤载。
  • 這兩個注解均在javax.annotation包中。
  • 為了注解可以生效吓蘑,需要在配置文件中定義org.springframework.context.annotation.CommonAnnotationBeanPostProcessorcontext:annotation-config

配置文件:

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />

代碼:

public class GiraffeService {
    @PostConstruct
    public void initPostConstruct(){
        System.out.println("執(zhí)行PostConstruct注解標(biāo)注的方法");
    }
 
    @PreDestroy
    public void preDestroy(){
        System.out.println("執(zhí)行preDestroy注解標(biāo)注的方法");
    }
 
}

方法4:配置全局默認(rèn)初始化惕虑、銷毀方法

default-init-method=" "
default-destroy-method=" "

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd" 
        default-init-method="defautInit" default-destroy-method="defaultDestroy">

 </beans>

Bean的生命周期示例

  • 定義一個Person
  • 實(shí)現(xiàn)了BeanNameAware,BeanFactoryAware,ApplicationContextAware,InitializingBean,DisposableBean五個接口
  • 在applicationContext.xml文件中配置了該Bean的id為person1,并且配置了init-methoddestroy-method,為該Bean配置了屬性name為jack的值
  • 然后定義了一個MyBeanPostProcessor方法,該方法實(shí)現(xiàn)了BeanPostProcessor接口,且在applicationContext.xml文件中配置了該方法的Bean,其代碼如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.2.xsd">
                    
     <bean id="person1" destroy-method="myDestroy" 
            init-method="myInit" class="com.test.spring.life.Person">
        <property name="name">
            <value>jack</value>
        </property>
    </bean>
    
    <!-- 配置自定義的后置處理器 -->
     <bean id="postProcessor" class="com.pingan.spring.life.MyBeanPostProcessor" />
</beans>
public class Person implements BeanNameAware, BeanFactoryAware,
        ApplicationContextAware, InitializingBean, DisposableBean {

    private String name;   
    public Person() {
        System.out.println("PersonService類構(gòu)造方法");
    }
    
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
        System.out.println("set方法被調(diào)用");
    }

    //自定義的初始化函數(shù)
    public void myInit() {
        System.out.println("myInit被調(diào)用");
    }
    
    //自定義的銷毀方法
    public void myDestroy() {
        System.out.println("myDestroy被調(diào)用");
    }

    public void destroy() throws Exception {
        // TODO Auto-generated method stub
     System.out.println("destory被調(diào)用");
    }

    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("afterPropertiesSet被調(diào)用");
    }

    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        // TODO Auto-generated method stub
       System.out.println("setApplicationContext被調(diào)用");
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        // TODO Auto-generated method stub
         System.out.println("setBeanFactory被調(diào)用,beanFactory");
    }

    public void setBeanName(String beanName) {
        // TODO Auto-generated method stub
        System.out.println("setBeanName被調(diào)用,beanName:" + beanName);
    }
    
    public String toString() {
        return "name is :" + name;
    }
public class MyBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean,
            String beanName) throws BeansException {
        // TODO Auto-generated method stub
        
        System.out.println("postProcessBeforeInitialization被調(diào)用");
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean,
            String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessAfterInitialization被調(diào)用");
        return bean;
    }

}
public class AcPersonServiceTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        System.out.println("開始初始化容器");
        ApplicationContext ac = new ClassPathXmlApplicationContext("com/test/spring/life/applicationContext.xml");
        
        System.out.println("xml加載完畢");
        Person person1 = (Person) ac.getBean("person1");
        System.out.println(person1);        
        System.out.println("關(guān)閉容器");
        ((ClassPathXmlApplicationContext)ac).close();
        
    }
}

我們啟動容器磨镶,可以看到整個調(diào)用過程:

開始初始化容器
九月 25, 2016 10:44:50 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@b4aa453: startup date [Sun Sep 25 22:44:50 CST 2016]; root of context hierarchy
九月 25, 2016 10:44:50 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [com/test/spring/life/applicationContext.xml]
Person類構(gòu)造方法
set方法被調(diào)用
setBeanName被調(diào)用,beanName:person1
setBeanFactory被調(diào)用,beanFactory
setApplicationContext被調(diào)用
postProcessBeforeInitialization被調(diào)用
afterPropertiesSet被調(diào)用
myInit被調(diào)用
postProcessAfterInitialization被調(diào)用
xml加載完畢
name is :jack
關(guān)閉容器
九月 25, 2016 10:44:51 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@b4aa453: startup date [Sun Sep 25 22:44:50 CST 2016]; root of context hierarchy
destory被調(diào)用
myDestroy被調(diào)用

Aware接口

有些時候我們需要在Bean的初始化中使用Spring框架自身的一些對象來執(zhí)行一些操作溃蔫,比如獲取ServletContext的一些參數(shù),獲取ApplicaitionContext中的BeanDefinition的名字琳猫,獲取Bean在容器中的名字等等伟叛。為了讓Bean可以獲取到框架自身的一些對象,Spring提供了一組名為___Aware接口脐嫂。

這些接口均繼承于org.springframework.beans.factory.Aware標(biāo)記接口统刮,并提供一個將由Bean實(shí)現(xiàn)的set___()方法,Spring通過基于setter的依賴注入方式使相應(yīng)的對象可以被Bean使用。

一些重要的Aware接口

接口 作用
ApplicationContextAware 獲得ApplicationContext對象,可以用來獲取所有Bean definition的名字
BeanFactoryAware 獲得BeanFactory對象账千,可以用來檢測Bean的作用域
BeanNameAware 獲得Bean在配置文件中定義的名字
ResourceLoaderAware 獲得ResourceLoader對象侥蒙,可以獲得classpath中某個文件
ServletContextAware 在一個MVC應(yīng)用中可以獲取ServletContext對象,可以讀取context中的參數(shù)
ServletConfigAware 在一個MVC應(yīng)用中可以獲取ServletConfig對象匀奏,可以讀取config中的參數(shù)

自動裝配(Autowiring)

具體參考
博客
為什么Spring要支持Autowire(自動裝配)

什么是裝配

在spring中鞭衩,對象無需自己查找或創(chuàng)建與其關(guān)聯(lián)的其他對象,容器負(fù)責(zé)把需要相互協(xié)作的對象引用賦予各個對象。
創(chuàng)建對象之間協(xié)作關(guān)系的行為通常稱為裝配论衍。

Spring 裝配的方式

  1. 隱式Bean的發(fā)現(xiàn)機(jī)制和自動裝配
    所謂自動裝配瑞佩,就是將一個Bean注入到其他Bean的Property中,類似于以下:
<bean id="customer" class="com.lei.common.Customer" autowire="byName" />
  1. 顯式裝配:
    • 在Java中顯式裝配
    • 在XML中顯式裝配

為什么自動裝配

Spring引入Autowire(自動裝配)機(jī)制就是為了解決<bean>標(biāo)簽下<property>標(biāo)簽過多的問題

5種自動裝配模式

模式 描述
no 默認(rèn)情況下坯台,不自動裝配炬丸,通過“ref”attribute手動設(shè)定
byName 由屬性名自動裝配。根據(jù)Property的Name自動裝配蜒蕾,如果一個bean的name稠炬,和另一個bean中的Property的name相同,則自動裝配這個bean到Property中
byType 由屬性數(shù)據(jù)類型自動裝配咪啡。根據(jù)Property的數(shù)據(jù)類型(Type)自動裝配酸纲,如果一個bean的數(shù)據(jù)類型,兼容另一個bean中Property的數(shù)據(jù)類型瑟匆,則自動裝配
constructor 根據(jù)構(gòu)造函數(shù)參數(shù)的數(shù)據(jù)類型,進(jìn)行byType模式的自動裝配
autodetect 如果發(fā)現(xiàn)默認(rèn)的構(gòu)造函數(shù)栽惶,用constructor模式愁溜,否則,用byType模式

Resource

簡介

在Spring內(nèi)部實(shí)現(xiàn)機(jī)制外厂,針對于資源文件(配置的xml文件)有一個統(tǒng)一的接口Resource

常用方法

方法 說明
exists() 用于判斷對應(yīng)的資源是否存在
isReadable() 用于判斷對應(yīng)資源的內(nèi)容是否可讀冕象。需要注意的是當(dāng)其結(jié)果為true的時候,其內(nèi)容未必真的可讀汁蝶,但如果返回false渐扮,則其內(nèi)容必定不可讀。
isOpen() 用于判斷當(dāng)前資源是否代表一個已打開的輸入流掖棉,如果結(jié)果為true墓律,則表示當(dāng)前資源的輸入流不可多次讀取,而且在讀取以后需要對它進(jìn)行關(guān)閉幔亥,以防止內(nèi)存泄露耻讽。該方法主要針對于InputStreamResource,實(shí)現(xiàn)類中只有它的返回結(jié)果為true帕棉,其他都為falses
getURL() 返回當(dāng)前資源對應(yīng)的URL针肥。如果當(dāng)前資源不能解析為一個URL則會拋出異常。如ByteArrayResource就不能解析為一個URL
getFile() 返回當(dāng)前資源對應(yīng)的File香伴。如果當(dāng)前資源不能以絕對路徑解析為一個File則會拋出異常慰枕。如ByteArrayResource就不能解析為一個File。
getInputStream() 獲取當(dāng)前資源代表的輸入流即纲。除了InputStreamResource以外具帮,其它Resource實(shí)現(xiàn)類每次調(diào)用getInputStream()方法都將返回一個全新的InputStream。

常用實(shí)現(xiàn)類

實(shí)現(xiàn)類 說明
ClassPathResource 獲取類路徑下的資源文件。假設(shè)有一個資源文件test.txt在類路徑下匕坯,new ClassPathResource("test.txt")
FileSystemResource 獲取文件系統(tǒng)里面的資源束昵。
UrlResource 可用來代表URL對應(yīng)的資源,它對URL做了一個簡單的封裝葛峻。通過給定一個URL地址锹雏,我們就能構(gòu)建一個UrlResource。
ByteArrayResource 針對于字節(jié)數(shù)組封裝的資源术奖,它的構(gòu)建需要一個字節(jié)數(shù)組礁遵。
ServletContextResource ServletContextResource持有一個ServletContext的引用,其底層是通過ServletContext的getResource()方法和getResourceAsStream()方法來獲取資源的
InputStreamResource 針對于輸入流封裝的資源采记,它的構(gòu)建需要一個輸入流

第四章 注解

Spring的一個核心功能是IOC佣耐,就是將Bean初始化加載到容器中,Bean是如何加載到容器的唧龄,可以使用Spring注解方式或者Spring XML配置方式兼砖。
Spring注解方式減少了配置文件內(nèi)容,更加便于管理既棺,并且使用注解可以大大提高了開發(fā)效率讽挟。
下面安裝分類講解Spring中常用的一些注解。

將普通類加入容器形成Bean

spring使用配置文件或者注解的方式進(jìn)行標(biāo)識需要處理的java類丸冕,從而知道哪些Java類當(dāng)bean類處理耽梅。

注解 標(biāo)注
@Component 標(biāo)準(zhǔn)一個普通的spring Bean類
@Repository 標(biāo)注一個DAO組件類
@Service 標(biāo)注一個業(yè)務(wù)邏輯組件類
@Controller 標(biāo)注一個控制器組件類

其中@Component、@Repository胖烛、@Service眼姐、@Controller實(shí)質(zhì)上屬于同一類注解,用法相同佩番,功能相同众旗,區(qū)別在于標(biāo)識組件的類型。

從容器中取Bean(裝配bean)

注解 標(biāo)注
@Autowired 屬于Spring 的org.springframework.beans.factory.annotation包下,可用于為類的屬性答捕、構(gòu)造器逝钥、方法進(jìn)行注值
@Resource 不屬于spring的注解,而是來自于JSR-250位于java.annotation包下拱镐,使用該annotation為目標(biāo)bean指定協(xié)作者Bean艘款。
@PostConstruct 和 @PreDestroy 方法 實(shí)現(xiàn)初始化和銷毀bean之前進(jìn)行的操作

Spring MVC模塊注解

@Controller---與前端交互

表明該類會作為與前端作交互的控制層組件

  • 通過服務(wù)接口定義的提供訪問應(yīng)用程序的一種行為,解釋用戶的輸入沃琅,將其轉(zhuǎn)換成一個模型然后將試圖呈獻(xiàn)給用戶
@Controller
public class HappyController {
    //do something
}

@RequestMapping---url --> 類或方法

  • 這個注解用于將url映射整個處理類或者特定的處理請求的方法
  • 可以只用通配符哗咆!
  • @RequestMapping中可以使用 method =屬性標(biāo)記其所接受的方法類型,如果不指定方法類型的話益眉,可以使用 HTTP GET/POST 方法請求數(shù)據(jù)晌柬,但是一旦指定方法類型姥份,就只能使用該類型獲取數(shù)據(jù)
@Controller
@RequestMapping("/happy")
public class HappyController  {

  @Autowired
  private HappyService happyService;

  @RequestMapping(/hello/ *)
  public void sayHello(){
        //請求為 /happy/hello/ * 都會進(jìn)入這個方法!
        //例如:/happy/hello/123   /happy/hello/adb
        //可以通過get/post 請求
  }

  @RequestMapping(value="/haha",method=RequestMethod.GET)
  public void sayHaHa(){
  //只能通過get請求
  }

}

第五章:Spring AOP

具體參考博客

AOP基本概念及特點(diǎn)

什么是AOP

AOP(Aspect Oriented Programming)意為:面向切面編程年碘,通過預(yù)編譯方式和運(yùn)行期動態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)澈歉。

主要功能是:日志記錄,性能統(tǒng)計(jì)屿衅,安全控制埃难,事務(wù)處理,異常處理等

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

  • 預(yù)編譯
    AspectJ
  • 運(yùn)行期間動態(tài)代理(JDK動態(tài)代理涤久、CGLib動態(tài)代理)
    SpringAOP涡尘、JbossAOP

AOP幾個關(guān)鍵概念

名稱 說明 舉例
切面(Aspect) 散落在系統(tǒng)各處的通用的非業(yè)務(wù)代碼 日志模塊,權(quán)限模塊响迂,事務(wù)模塊
連接點(diǎn)(Joinpoint) 被攔截到的點(diǎn) Spring只支持方法類型的連接點(diǎn)考抄,所以在Spring中連接點(diǎn)指的就是被攔截到的方法
通知(Advice) 攔截到連接點(diǎn)之后要執(zhí)行的代碼 分為前置、后置蔗彤、異常川梅、最終、環(huán)繞通知五類
切入點(diǎn)(Pointcut) 攔截的方法然遏,連接點(diǎn)攔截后變成切入點(diǎn) 帶有通知的連接點(diǎn)
織入(weave) 通過切入點(diǎn)切入挑势,將切面應(yīng)用到目標(biāo)對象并導(dǎo)致代理對象創(chuàng)建的過程 ?
目標(biāo)對象(Target Object) 代理的目標(biāo)對象,指要織入的對象模塊 業(yè)務(wù)代碼
AOP代理(AOP Proxy) AOP框架創(chuàng)建的對象(包括通知方法執(zhí)行等功能) Spring中的AOP代理可以使JDK動態(tài)代理啦鸣,也可以是CGLIB代理,前者基于接口来氧,后者基于子類

各關(guān)鍵概念具體介紹

Advice

說明:

類型 說明
前置通知(Before advcie) 在某連接點(diǎn)(join point)之前執(zhí)行的通知诫给,但不能阻止連接點(diǎn)前的執(zhí)行(除非它拋出一個異常)
返回后通知(After returning advice) 在某連接點(diǎn)(join point)正常執(zhí)行完成后執(zhí)行的通知
拋出異常后通知(After throwing advice) 在方法拋出異常退出時執(zhí)行的通知
后通知(After(finally)advice) 當(dāng)某個連接點(diǎn)退出的時候執(zhí)行的通知(不論是正常返回還是異常退出)
環(huán)繞通知(Around Advice) 包圍一個連接點(diǎn)(join point)的通知

使用方式:

名稱 配置中使用 注解中使用
前置通知(Before advcie) <aop:aspect>里面使用<aop:before> @Before
返回后通知(After returning advice) <aop:aspect>里面使用<aop:after-returning> @AfterReturning
拋出異常后通知(After throwing advice) <aop:aspect>里面使用<aop:after-throwing> @AfterThrowing
后通知(After(finally)advice) aop:aspect>里面使用<aop:after>元素 @After
環(huán)繞通知(Around Advice) <aop:aspect>里面使用<aop:around> @Around

通知執(zhí)行順序:

前置通知→環(huán)繞通知連接點(diǎn)之前→連接點(diǎn)執(zhí)行  1→  環(huán)繞通知連接點(diǎn)之后→返回通知→后通知
                                     2→  (如果發(fā)生異常)異常通知→后通知

pointcut

切入點(diǎn)表達(dá)式 說明
execution 用于匹配方法執(zhí)行的連接點(diǎn)
within 用于匹配指定類型內(nèi)的方法執(zhí)行
this 用于匹配當(dāng)前AOP代理對象類型的執(zhí)行方法;this中使用的表達(dá)式必須是完整類名啦扬,不支持通配符
target 用于匹配當(dāng)前目標(biāo)對象類型的執(zhí)行方法中狂;注意是目標(biāo)對象的類型匹配,這樣就不包括引入接口也類型匹配扑毡;注意target中使用的表達(dá)式必須是完整類名胃榕,不支持通配符;
args 用于匹配當(dāng)前執(zhí)行的方法傳入的參數(shù)為指定類型的執(zhí)行方法瞄摊;參數(shù)類型列表中的參數(shù)必須是完整類名勋又,通配符不支持;args屬于動態(tài)切入點(diǎn)换帜,這種切入點(diǎn)開銷非常大楔壤,非特殊情況最好不要使用;
@within 用于匹配所有持有指定注解類型內(nèi)的方法惯驼;注解類型也必須是完整類名蹲嚣;
@target 用于匹配當(dāng)前目標(biāo)對象類型的執(zhí)行方法递瑰,其中目標(biāo)對象持有指定的注解;注解類型也必須是完整類名隙畜;
@args 用于匹配當(dāng)前執(zhí)行的方法傳入的參數(shù)持有指定注解的執(zhí)行抖部;注解類型也必須是完整類名;
@annotation 用于匹配當(dāng)前執(zhí)行方法持有指定注解的方法议惰;注解類型也必須是完整類名慎颗;
bean Spring AOP擴(kuò)展的,AspectJ沒有對于指示符换淆,用于匹配特定名稱的Bean對象的執(zhí)行方法哗总;
reference pointcut 表示引用其他命名切入點(diǎn),只有注解風(fēng)格支持倍试,XML風(fēng)格不支持讯屈。

定義

  • 一個切入點(diǎn)通過一個普通的方法定義來提供,使用@Pointcut注解

  • 方法返回類型必須為void

  • eg.
    定義一個名為‘a(chǎn)nyOldTransfer’县习,這個切點(diǎn)將匹配任何名為”transfer“的方法執(zhí)行@Pointcut("execution(* transfer(..))")//the pointcut expression

@Pointcut("execution(* transfer(..))")//the pointcut expression
private void anyOldTransfer(){}//the pointcut signature

組合pointcut

  • 切入點(diǎn)表達(dá)式可以通過&&涮母、||、!進(jìn)行組合躁愿,也可以通過名字引入切入點(diǎn)表達(dá)式
  • 通過組合叛本,可以建立更加復(fù)雜的切入點(diǎn)表達(dá)式
@Pointcut("execution(public * (..))")
private void anyPublicOperation(){}

@Pointcut("within(com.xyz.someapp.trading...)")
private void inTrading(){}

@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation(){}

匹配語法

符號 匹配
* 匹配任何數(shù)量字符
.. 匹配任何數(shù)量字符的重復(fù),如在類型模式中匹配任何數(shù)量子包彤钟;而在方法參數(shù)模式中匹配任何數(shù)量參數(shù)来候。
+ 匹配指定類型的子類型;僅能作為后綴放在類型模式后邊逸雹。
例子 匹配 不匹配
java.lang.String 匹配String類型 ?
java.*.String 匹配java包下的任何“一級子包”下的String類型营搅;如匹配java.lang.String 但不匹配java.lang.ss.String
java..* 匹配java包及任何子包下的任何類型;如匹配java.lang.String梆砸、java.lang.annotation.Annotation ?
java.lang.*ing 匹配任何java.lang包下的以ing結(jié)尾的類型 ?
java.lang.Number+ 匹配java.lang包下的任何Number的自類型转质;如匹配java.lang.Integer,也匹配java.math.BigInteger ?

實(shí)現(xiàn)手法

環(huán)境

Spring中AOP代理由Spring的IOC容器負(fù)責(zé)生成帖世、管理休蟹,其依賴關(guān)系也由IOC容器負(fù)責(zé)管理,要在Spring 中使用AOP日矫,還需要加入這兩個jar包
1赂弓、aopalliance.jar
2、aspectjweaver.jar

Spring中 AOP中的兩種代理

  1. Java動態(tài)代理
    默認(rèn)使用 哪轿〖鹫梗可以為任何接口實(shí)例創(chuàng)建代理了
  2. CGLIB
    當(dāng)需要代理的類不是代理接口的時候,Spring會切換為使用CGLIB代理缔逛,也可強(qiáng)制使用CGLIB

Spring AOP的使用步驟

  1. 定義具體業(yè)務(wù)邏輯模塊(目標(biāo)對象)
  2. 定義切面(即實(shí)現(xiàn)通知邏輯)
  3. 實(shí)現(xiàn)切面邏輯

兩種方式的例子

兩種方式备埃,基于Schema或@AspectJ姓惑。

一. 基于Schema的Spring AOP

第一步、定義具體業(yè)務(wù)模塊(目標(biāo)對象)

兩個業(yè)務(wù)模塊都是基于接口

TestAOPDaoImpl .java

public class TestAOPDaoImpl implements TestAOPDao{

    @Override
    public void addUser() {
        System.out.println("添加成功");
    }
}

TestAOPServiceImpl.java

public class TestAOPServiceImpl implements TestAOPService{

    @Autowired
    private TestAOPDao testAOPDao;

    @Override
    public void addUser() {
        testAOPDao.addUser();
    }
}

第二步和第三步按脚、 定義切面(即實(shí)現(xiàn)通知邏輯)

aop創(chuàng)建代理后會返回一個 連接點(diǎn)JointPoint于毙,然后在通知中可以通過該連接點(diǎn)實(shí)現(xiàn)我們的切面邏輯

日志切面

public class LogAdivice{

    public void myBeforeAdivice(JoinPoint joinPoint){
        String classname = joinPoint.getTarget().getClass().getSimpleName();
        String methodname = joinPoint.getSignature().getName();
        System.out.println(classname + " ——前置通知——" + methodname);
    }

    public void myAfterAdivice(JoinPoint joinPoint){
        String classname = joinPoint.getTarget().getClass().getSimpleName();
        String methodname = joinPoint.getSignature().getName();
        System.out.println(classname + " ——后置通知——" + methodname);
    }

   //環(huán)繞通知將決定要不要執(zhí)行連接點(diǎn)
    public void myAroundAdivice(ProceedingJoinPoint point) throws Throwable{
        System.out.println("環(huán)繞通知,執(zhí)行代碼前");
        //選擇執(zhí)行
        point.proceed();
        System.out.println("環(huán)繞通知辅搬,執(zhí)行代碼后");
    }
}

時間切面:

public class TimeAdvice {

    public void timeBefore(){
        System.out.println("beforeTime = " + System.currentTimeMillis());
    }

    public void timeAfter(){
        System.out.println("afterTime = " + System.currentTimeMillis());
    }
}

在applicationContext中配置切面:

<context:annotation-config/>
    <bean id="testAOPDao" class="com.ssh.dao.impl.TestAOPDaoImpl"/>
    <bean id="testAOPService" class="com.ssh.service.impl.TestAOPServiceImpl"/>
    <bean id="logAdivice" class="com.ssh.adivice.LogAdivice"/>
    <bean id="timeAdvice" class="com.ssh.adivice.TimeAdvice"/>

    <aop:config>
       <!-- 配置一個切面 -->
       <aop:aspect id="logaop" ref="logAdivice" order="2">
           <!-- 定義切入點(diǎn)唯沮,表示對service的所有方法都進(jìn)行攔截 -->
           <aop:pointcut expression="execution(* com.ssh.service.TestAOPService.*(..))" id="testpointcut"/>
           <!-- 定義前置通知 -->
           <aop:before method="myBeforeAdivice" pointcut-ref="testpointcut"/>
           <!-- 定義后置通知 -->
           <aop:after-returning method="myAfterAdivice" pointcut-ref="testpointcut"/>
           <!-- 定義環(huán)繞通知 -->
           <aop:around method="myAroundAdivice" pointcut-ref="testpointcut"/>
       </aop:aspect>

       <!-- 定義另一個切面 -->
       <aop:aspect id="timeaop" ref="timeAdvice" order="1">
           <!-- 定義切入點(diǎn),表示對service的所有方法都進(jìn)行攔截 -->
           <aop:pointcut expression="execution(* com.ssh.service.TestAOPService.*(..))" id="testpointcut"/>
           <!-- 定義前置通知 -->
           <aop:before method="timeBefore" pointcut-ref="testpointcut"/>
           <!-- 定義后置通知 -->
           <aop:after-returning method="timeAfter" pointcut-ref="testpointcut"/>
       </aop:aspect>
    </aop:config>

當(dāng)有多個切面時堪遂,Spring默認(rèn)是按照切面定義的順序來執(zhí)行介蛉,也可以通過order屬性來配置切面的執(zhí)行屬性,order=1 早于 order=2執(zhí)行

測試

public class AOPTest {
    public static void main(String[] args) {
        ApplicationContext context = new 
                            ClassPathXmlApplicationContext("applicationContext.xml");
        TestAOPService service = (TestAOPService) context.getBean("testAOPService");
        service.addUser();
    }
}

二. 基于@AspectJ注解的AOP實(shí)現(xiàn)

啟用@AsjectJ支持

在applicationContext.xml中配置下面一句:

<aop:aspectj-autoproxy />

第一步溶褪、定義具體業(yè)務(wù)邏輯模塊(目標(biāo)對象)

第一步和基于Schema的一樣

TestAOPDaoImpl .java

public class TestAOPDaoImpl implements TestAOPDao{

    @Override
    public void addUser() {
        System.out.println("添加成功");
    }
}

TestAOPServiceImpl.java

public class TestAOPServiceImpl implements TestAOPService{

    @Autowired
    private TestAOPDao testAOPDao;

    @Override
    public void addUser() {
        testAOPDao.addUser();
    }
}

第二步和第三步 定義切面(即實(shí)現(xiàn)通知邏輯)

重點(diǎn)是定義切入點(diǎn)

@Aspect
public class LogAdivice{

    //定義一個方法作為切入點(diǎn)id
    @Pointcut("execution(* com.ssh.service.TestAOPService.*(..))")
    private void allMethod(){}

    @Before("allMethod()")
    public void myBeforeAdivice(JoinPoint joinPoint){
        String classname = joinPoint.getTarget().getClass().getSimpleName();
        String methodname = joinPoint.getSignature().getName();
        System.out.println(classname + " ——前置通知——" + methodname);
    }

    @AfterReturning("allMethod()")
    public void myAfterAdivice(JoinPoint joinPoint){
        String classname = joinPoint.getTarget().getClass().getSimpleName();
        String methodname = joinPoint.getSignature().getName();
        System.out.println(classname + " ——后置通知——" + methodname);
    }

  //環(huán)繞通知將決定要不要執(zhí)行連接點(diǎn)
    @Around("allMethod()")
    public void myAroundAdivice(ProceedingJoinPoint point) throws Throwable{
        System.out.println("環(huán)繞通知币旧,執(zhí)行代碼前");
        //執(zhí)行
        point.proceed();
        System.out.println("環(huán)繞通知,執(zhí)行代碼后");
    }
}

在applicationContext的配置:

<!-- 打開自動掃描(隱式打開注解管理器) -->
    <!-- <context:component-scan base-package="com.ssh"/> -->
    <context:annotation-config/>
    <bean id="testAOPDao" class="com.ssh.dao.impl.TestAOPDaoImpl"/>
    <bean id="testAOPService" class="com.ssh.service.impl.TestAOPServiceImpl"/>
    <bean id="logAdivice" class="com.ssh.adivice.LogAdivice"/>
    <bean id="timeAdvice" class="com.ssh.adivice.TimeAdvice"/>

    <!-- 打開aop注解管理器 -->
    <aop:aspectj-autoproxy/>

參考文章在各個小結(jié)中有鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末猿妈,一起剝皮案震驚了整個濱河市吹菱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌彭则,老刑警劉巖鳍刷,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異俯抖,居然都是意外死亡输瓜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門芬萍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來前痘,“玉大人,你說我怎么就攤上這事担忧。” “怎么了坯癣?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵瓶盛,是天一觀的道長。 經(jīng)常有香客問我示罗,道長惩猫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任蚜点,我火速辦了婚禮轧房,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绍绘。我一直安慰自己奶镶,他們只是感情好迟赃,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著厂镇,像睡著了一般纤壁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捺信,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天酌媒,我揣著相機(jī)與錄音,去河邊找鬼迄靠。 笑死秒咨,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掌挚。 我是一名探鬼主播雨席,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼疫诽!你這毒婦竟也來了舅世?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤奇徒,失蹤者是張志新(化名)和其女友劉穎雏亚,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摩钙,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡罢低,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了胖笛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片网持。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖长踊,靈堂內(nèi)的尸體忽然破棺而出功舀,到底是詐尸還是另有隱情,我是刑警寧澤身弊,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布辟汰,位于F島的核電站,受9級特大地震影響阱佛,放射性物質(zhì)發(fā)生泄漏帖汞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一凑术、第九天 我趴在偏房一處隱蔽的房頂上張望翩蘸。 院中可真熱鬧,春花似錦淮逊、人聲如沸催首。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翅帜。三九已至姻檀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涝滴,已是汗流浹背绣版。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留歼疮,地道東北人杂抽。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像韩脏,于是被迫代替她去往敵國和親缩麸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

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

  • 控制反轉(zhuǎn): 把創(chuàng)建對象的權(quán)利交給框架,在使用過程中直接去得到這個對象赡矢;它包括依賴注入(Dependency Inj...
    _Sisyphus閱讀 242評論 1 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理杭朱,服務(wù)發(fā)現(xiàn),斷路器吹散,智...
    卡卡羅2017閱讀 134,693評論 18 139
  • IoC 容器 Bean 的作用域 自定義作用域?qū)崿F(xiàn) org.springframework.beans.facto...
    Hsinwong閱讀 2,475評論 0 7
  • 什么是Spring Spring是一個開源的Java EE開發(fā)框架弧械。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,473評論 1 133
  • 尊敬的閆老師: 您好,看了您的那封信以后我覺得這個活動對我的作文的水平有著很大的幫助空民。 開始寫的時候刃唐,我并不知道自...
    藺佳宇ljy閱讀 275評論 3 2