【Spring IOC&DI】知识点详细介绍

Spring

简介

  • Spring是一个IOC(DI)和AOP容器框架

  • IOC(DI):依赖注入

  • AOP:面向切面编程

Spring Framework 系统架构

image
  • Text:Spring的单元测试模块

  • Core Container:核心容器(IOC);黑色代表这部分的功能由哪些jar包组成

  • AOP+Aspects(面向切面编程模块)

  • ORM(Object Relation Mapping):对象关系映射

  • Transaction:事务

IOC & DI


简介

IOC:(Inversion(反转) Of Control):控制反转

DI:(Dependency Injection)依赖注入


通过IOC容器创建对象,并为属性赋值


<!--一个Bean标签可以注册一个组件(类、对象)-->

<!-- class:组件的全类名  id:唯一标识 -->

<bean id="person1" class="com.bean.Person">

    <!--使用property标签为Person对象的属性赋值-->

    <!-- name="" : 指定属性名 value="" :指定属性的值-->

<property name="personName" value="张三" ></property>

    <property name="personAge" value="18" ></property>

</bean>


public void test(){

    //ApplicationContext 代表ioc容器

    //ClassPathXmlApplicationContext:当前应用的xml配置文件在ClassPath下

    //根据配置文件得到ioc容器对象

    ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml");

    Person person = (Person)ioc.getBean("person1");

}

注意!

  1. 容器中对象的创建在容器创建的时候就已经创建好了

  2. 同一个组件在ioc容器中是单实例的

  3. ioc容器在创建这个组件对象的时候,会利用setter方法为javabean的属性进行赋值

  4. javaBean的属性名是由getter/setter方法决定的


根据bean的类型从IOC容器中获取bean的实例


<bean id="person1" class="com.bean.Person">

<property name="personName" value="张三" ></property>

    <property name="personAge" value="18" ></property>

</bean>

<bean id="person2" class="com.bean.Person">

<property name="personName" value="小花" ></property>

    <property name="personAge" value="18" ></property>

</bean>


public void test(){

    ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml");

    //如果ioc容器中这个类型的bean有多个,查找就会报错

    Person person = ioc.getBean(Person.class);

    //这样使用 即便ioc容器中这个类型的bean有多个,查找也不会报错

    Person person = ioc.getBean("person1",Person.class);

}


通过构造器为bean的属性赋值

调用有参构造器创建对象并赋值


<bean id="person1" class="com.bean.Person">

<constructor-arg name="personName" value="张三"></constructor-arg>

    <constructor-arg name="personAge" value="18"></constructor-arg>

    <!--此处可以省略name属性,但需要按照构造器参数的顺序指定value值-->

    <constructor-arg  value="张三"></constructor-arg>

    <constructor-arg  value="18"></constructor-arg>

    <!--index="0" 为参数指定索引 从0开始-->

    <constructor-arg  value="张三" index="0"></constructor-arg>

    <constructor-arg  value="18" index="1"></constructor-arg>

    <!--如果有多个有参构造器  使用type指定参数类型-->

    <constructor-arg  value="张三" index="0"></constructor-arg>

    <constructor-arg  value="18" index="1" type="java.lang.Integer"></constructor-arg>

</bean>


public void test(){

    ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml");

    Person person = ioc.getBean("person1");

}


通过p名称空间为bean赋值

名称空间:在xml中名称空间是用来防止标签重复的


<!--使用p名称空间赋值时,需先导入p名称空间-->

<bean id="person1" class="com.bean.Person" p:personName="张三" p:personAge="18">



</bean>


为复杂类型的属性赋值


//实体类

public class Person{

    private String name;

    private int age;



    private Car car;//Car是一个实体类

    private List<Book> books;//Book是一个实体类

    private Map<String,Object> maps;

    private Properties properties;



}


<bean id="car" class="com.bean.Car">

<property name="carNmae" value="宝马"></property>

</bean>

<bean id="book" class="com.bean.Book">

<property name="bookNmae" value="西游记"></property>

</bean>

<bean id="person1" class="com.bean.Person">

    <!--赋值为null-->

    <property name="name">

    <null/>

    </property>



    <!--ref="car" 这是一个严格的引用 person中的car跟 直接从容器中获取的car是一样的-->

    <property name="car" ref="car"></property>



    <!--为list类型赋值-->

    <property name="books">

    <list>

            <!--内部bean 写id和不写id是一样的  外部获取不到-->

        <bean id="book" class="com.bean.Book" p:bookName="西游记"></bean>



            <ref bean="book"/>

        </list>

    </property>



    <!--为map类型赋值-->

    <bean id="maps">

        <!--底层用的是LinkedHashMap-->

<map>

            <!--一个entry代表一个键值对-->

        <entry key="key1"value="value1"></entry>

            <entry key="key2"value="value2"></entry>

            <entry key="key3"value-ref="book"></entry>

            <entry key="key4">

                <!--内部bean无法用id获取 无论是否有id-->

            <bean id="" class="com.bean.Car">

                <property name="carName" value="宝马"></property>

                </bean>

            </entry>

        </map>

</bean>



    <!--为Properties类型赋值-->

    <bean name="properties">

        <!--properties 里面 所有的k=v都是String类型-->

    <props>

        <prop key="username">root</prop>

            <prop key="username">123456</prop>

        </props>

    </bean>

</bean>


级联属性赋值


<bean id="car01" class="cam.bean.Car">

    <property name="carName" value="宝马"></property>

</bean>

<bean id="person" class="cam.bean.Person">

<property name="car" ref="car01"></property>

    <property name="car.carName" value="奔驰"></property>

</bean>

注意

  1. 级联属性可以修改属性的属性,但是原来的bean值将会被修改

通过继承实现bean配置信息的重用


<bean id="person1" class="com.bean.Person">

<property name="perName" value="张三"></property>

    <property name="perAge" value="15"></property>

    <property name="perGender" value="男"></property>

</bean>

<!--parent="" : 指定当前的bean的配置信息继承于哪个bean    class=""可以省略不写 -->

<bean id="person2" class="com.bean.Person" parent="person1">

<property name="perName" value="张三"></property>

</bean>

<!--abstract="true" 表示这个bean只能被继承 不可以获取-->

<bean id="person3" class="com.bean.Person" parent="person1" abstract="true">

<property name="perGender" value="男"></property>

</bean>


IOC容器中改变bean的创建顺序


<!--原来是按照配置的顺序创建bean-->

<bean id="person" class="com.bean.Person"></bean>

<bean id="car" class="com.bean.Car"></bean>

<bean id="book" class="com.bean.Book"></bean>

<!-- depends-on="car,book" 改变bean的创建顺序-->

<bean id="person" class="com.bean.Person" depends-on="car,book"></bean>

<bean id="car" class="com.bean.Car"></bean>

<bean id="book" class="com.bean.Book"></bean>


bean的作用域


<bean id="book" class="com.bean.Book" scope=""></bean>

scope="" 设置作用域 默认所有的bean都是单实例的

  • prototype:多实例的

    • 多实例的bean,容器启动默认不会去创建多实例的bean

    • 只有在获取的时候才会创建这个bean

    • 每次获取都会创建一个新的对象

  • singleton:单实例的 默认的

    • 单实例的bean在容器启动完成之前就已经创建好对象,并保存在容器中了

    • 单实例的bean从始至终 获取到的都是之前创建好的那个对象

  • request:在web环境下,同一个请求创建一个Bean实例(没用)

  • session:在web环境下,同一次会话创建一个Bean实例(没用)


静态工厂和实例工厂创建bean

静态工厂:工厂本身不用创建对象,通过静态方法调用,对象 = 工厂类.工厂方法名();


public class AirPlaneStaticFactory{

    //这个方法是静态方法

    public static AirPlane getAirPlane(String planeName){

        AirPlane airplane = new AirPlane();

    airplane.setPlaneName(planeName);

        return airPlane;

    }

}


<!--静态工厂(不需要创建工厂本身)

1.class指定静态工厂全类名,

2.factory-method 指定工厂方法,

3.constructor-arg 可以为方法传参   -->

<bean id="airPlane" class="com.factory.AirPlaneStaticFactory" factory-method="getAirPlane">

<constructor-arg name="planeName" value="大飞机1号" ></constructor-arg>       

</bean>


public void test(){

    ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml");

    //获取到的是飞机  并不是工厂

    AirPlane airplane = ioc.getBean("airPlane");

}

实例工厂:工厂本身需要创建对象,

​ 工厂类 工厂对象 = new 工厂类();

​ 对象 =工厂对象.工厂方法名();


public class AirPlaneInstanceFactory{

    //这个方法不是静态方法

    public AirPlane getAirPlane(String planeName){

        AirPlane airplane = new AirPlane();

    airplane.setPlaneName(planeName);

        return airPlane;

    }

}


<!--实例工厂(需要创建工厂本身)-->

<bean id="airPlaneInstanceFactory" class="com.factory.AirPlaneInstanceFactory">     

</bean>

<!--factory-bean="" 指定当前对象由哪个工厂创建 factory-method=""指定工厂方法-->

<bean id="airPlane" class="com.bean.AirPlane" factory-bean="airPlaneInstanceFactory" factory-method="getAirPlane">

<constructor-arg name="planeName" value="大飞机2号" ></constructor-arg>

</bean>


public void test(){

    ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml");

    //获取到的是飞机  并不是工厂

    AirPlane airplane = ioc.getBean("airPlane");

}


实现FactoryBean接口的工厂

FactoryBean 是Spring规定的一个接口,只要是这个接口的实现类 ,spring都认为是一个工厂,Spring会自动调用工厂方法创建实例

第一步:需要写一个实现了FactoryBean接口的类


public class MyFactoryBeanImpl implements FactoryBean<Book>{

    //getObject:工厂方法 返回创建的对象

    @Override

    public Book getObject() throws Exception{

        Book book = new Book();

        book.setId(1);

        return book;

    }

    //返回 创建的对象的类型

    @Override

    public Class<?> getObjectType(){

        return Book.class;

    }

    //返回  是否是单例

    //false : 不是单例  true: 是单例

    @Override

    public boolean isSingleton(){

        return false;

    }

}

第二步:在配置文件中进行注册


<!-- 注意!:无论 isSingleton()这个方法返回值是什么  ioc容器启动的时候不会创建这个实例-->

<bean id="myFactoryBeanImpl" class="com.factory.MyFactoryBeanImpl"></bean>

**注意 获取到的是book对象 **


public void test(){

    ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml");

    //获取到的是book对象

    Book book = ioc.getBean("myFactoryBeanImpl");

}


创建带有生命周期方法的bean

  • 生命周期:bean的创建到销毁,我们可以自定义一些生命周期方法,spring在创建或销毁的时候会调用指定的方法

  • 自定义初始化方法和销毁方法,但是不可以有参数 可以抛异常

  • 单例Bean的生命周期

    • (容器启动)构造器——>>>初始化方法——>>>(容器关闭)销毁方法

<bean id="book" class="com.bean.Book" destory-method="" init-method="" >

</bean>

  • 多例Bean的生命周期

    • (获取bean)构造器——>>>初始化方法——>>>(容器关闭)不会调用bean的销毁方法

<bean id="book" class="com.bean.Book" destory-method="" init-method="" scope="protorype" >

</bean>


spring管理连接池

​ 数据库链接池作为单实例是最好的,一个项目就一个连接池,连接池里面管理很多链接,链接是直接从链接池里面拿

​ 可以让Spring帮我们创建连接池对象 管理连接池


<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

<property name="user" value="root"></property>

    <property name="password" value="123456"></property>

    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>

    <property name="driverClass" value="com.mysql.jdbc.Driver"></property>

</bean>

spring管理连接池引用外部配置文件

jdbc.properties


#username=root

jdbc.username=root

jdbc.password=123456

jdbc.jdbcUrl=jdbc:mysql://localhost:3306/test

jdbc.driverClass=com.mysql.jdbc.Driver

在ApplicationContext.xml中配置时 需要引入context命名空间

注意!

  • username 是spring中的一个关键字 在这里不可以使用username**

  • value="${jdbc.username}" 引号前后不能有空格


<!--加载外部配置文件的 classpath: 表示引用类路径下的配置文件-->

<context:property-placeholder location="classpath:jdbc.properties" />

<!--username 是spring中的一个关键字 在这里不可以使用username-->

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

<!--<property name="user" value="${username}"></property>-->

    <property name="user" value="${jdbc.username}"></property>

    <property name="password" value="${jdbc.password}"></property>

    <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>

    <property name="driverClass" value="${jdbc.driverClass}"></property>

</bean>


基于xml的自动装配

**注意!自动装配仅限于自定义类型的属性 **


<bean id="car" class="com.bean.Car">

<property name="carName" value="宝马"></property>

    <property name="color" value="白色"></property>

</bean>

<!--

autowire=""

default/no:不自动装配,不自动为car属性赋值

  byName:以属性名作为id去容器中找到一个组件,给他赋值,如果找不到就赋值null

byType:以属性的类型作为查找依据去容器中找到这个组件,如果容器中有多个这样的类型会报错

constructor:按照有参构造器为car赋值

1.先按照有参构造器参数类型进行装配,没有就直接为组件装配null

2.如果按照类型找到了多个bean:以参数的名作为id继续装配,找不到就null

假设有一个List<Book> books属性,容器可以把容器中所有的book封装进list

-->

<bean id="person" class="com.bean.Person" autowire="default"></bean>


SpEL(Spring Expression Language)spring表达式语言

表达式语言

  • 字面量:#{125}*

  • 引用其他bean的某个属性值:#{car.carName}

  • 引用其他bean:#{car}

  • 调用非静态方法:#{对象.方法名(arg1,arg2)} eg:#{car.getCarName()}

  • 调用静态方法:#{T(全类名).静态方法名(arg1,arg2)} eg: #{T(java.util.UUID).randomUUID().toString()}


<bean id="car" class="com.bean.Person">

<property name="carName" value="宝马"></property>

</bean>

<bean id="person" class="com.bean.Person">

<property name="age" value="#{12*5}"></property>

    <property name="perName" value="#{car.carName}"></property>

    <property name="car" value="#{car}"></property>

    <property name="email" value="#{T(java.util.UUID).randomUUID().toString()}"></property>

    <property name="testName" value="#{car.getCarName()}"></property>

</bean>


通过注解分别创建Controller、Dao、Service

spring有四个注解某个类上注解任何一个都可以讲这个组件加入到ioc容器中

  • @Controller

    • 推荐给控制器层(servlet)的组件加这个注解
  • @Service

    • 推荐给业务逻辑层的组件加这个注解 Service层
  • @Repository

    • 推荐给数据库层(持久化层,dao层)的组件添加这个注解
  • @Component

    • 给不属于以上几层的组件添加这个注解

使用注解将组价快速加入到容器中需要几步

  1. 给要添加的组件上标上以上四个注解之一

  2. 告诉spring,自动扫描加了注解的组件,依赖context命名空间


<!--自动组件扫描-->

<!--base-package="" 指定扫描的基础包-->

<context:component-scan base-package=""></context:component-scan>

  • 使用context:exclude-filter指定扫描包时不包含的类

    • 扫描的时候可以排除一些不要的组件

    • type="annotation":按照注解进行排除-->标注了指定注解的组建不要

      expression="":注解的全类名

    • type="assignable":按照类进行排除

      expression="":类的全类名

    • type="aspectj":aspectj表达式(很少用)

    • type="custom":自定义一个TypeFilter;自己写代码决定哪些使用(很少用)

    • type="regex":正则表达式(很少用)


<context:component-scan base-package="">

    <!--表示标注了@controller的注解不进行扫描-->

<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>

    <!--表示com.controller.BookController这个类不进行扫描-->

<context:exclude-filter type="assignable" expression="com.controller.BookController"/>

</context:component-scan>

  • 使用context:include-filter指定扫描包时包含的类

    • 指定只扫描哪些组件,

    • 注意!需要使用 use-default-filters="false" 取消默认行为

    • type="annotation":按照注解进行排除-->标注了指定注解的组建不要

      expression="":注解的全类名

    • type="assignable":按照类进行排除

      expression="":类的全类名

    • type="aspectj":aspectj表达式(很少用)

    • type="custom":自定义一个TypeFilter;自己写代码决定哪些使用(很少用)

    • type="regex":正则表达式(很少用)


<context:component-scan base-package="" use-default-filters="true">

    <!--表示只有标注了@controller的注解进行扫描-->

<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>

    <!--表示只有com.controller.BookController这个类进行扫描-->

<context:include-filter type="assignable" expression="com.controller.BookController"/>

</context:component-scan>

  1. 一定要导入AOP包 支持加注解模式

这里bean的id默认就是类名首字母小写

使用注解加入到容器中的组件,和使用配置加入到容器中的组件行为都是默认一样的:

  • 组件的id,默认就是类名首字母小写

  • 组件的作用域,默认就是单例的


public void test(){

    ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml");

    Object bean = ioc.getBean("");

}

注意,如果想要修改默认行为

  • 修改bean的Id

@Repository("你想要的id名")  四个注解都是一样的

  • 修改作用域

@Scope(value="prototype") 


使用@Autowired注解实现自动装配

@Autowired为bookservice自动赋值


@Controller

public class BookServlet{

    @Autowired

    private BookService bookService;

}

@Autowired原理

  1. 按照类型去容器中找到对应的组件;bookService = ioc.getBean("BookService.class");

  2. 如果找到了就直接赋值

  3. 没找到就抛出异常

  4. 如果找到多个,就按照变量名作为id继续匹配

    1. 如果匹配上就赋值

    2. 如果没有匹配上,就抛出异常。

    3. 注意!这里可以使用@Qualifier注解 作用是可以指定一个名称作为id,取消spring使用变量名作为id的行为。eg:@Qualifier(“newbookservice“)

    4. 如果找到就装配

    5. 如果找不到,就抛出异常

注意!

可以使用required=false 来解决 如果@Autowired找不到指定bean 就赋值为null

@Autowired(required=false)


在方法上使用@Autowired注解并在形参位置使用@Qualifier

  • 方法上有@Autuwired

    • 这个方法会在容器创建的时候自动运行

    • 这个方法的每一个参数都会自动注入值


@Autowired

public void methods(@Qualifier("newbookservice")BookService bookservice){

    System.out.println("")

}


@Autowired 和 @Resource的区别

  • @Autowired 和 @Resource 和 @Inject都是自动装配的意思
  • @Autowired最强大:Spring自己的注解

  • @Resource:j2ee java的标准 ,扩展性更强 因为如果我们切换另外一个容器框架@Resource还是可以使用,但是@Autowired离开了spring 就不能使用了


Spring的单元测试

  1. 导包 导入spring-test-4.0.0

  2. @ContextConfiguration使用这个注解来指定spring的配置文件的位置

  3. @RunWith()指定用哪种驱动进行单元测试。默认就是junit

​ @RunWith(SpringJUnit4ClassRunner.class)

​ 使用spring的单元测试模块来执行标注了@Test注解的测试方法

​ 以前的@Test只是由JUnit执行


@ContextConfiguration(locations="classpath:spring.xml")

@RunWith(SpringJUnit4ClassRunner.class)

public class SpringTest{

    ApplicationContext ac = null;



    @Autowired

    BookServlet bookServlet;

}


泛型依赖注入

泛型依赖注入,注入一个组件的时候,他的泛型也是参考标准

image
  • 首先BookDao和UserDao都继承BaseDao<T>这个抽象类并实现抽象方法

public abstract class BaseDao<T>{

    public abstract void save();

    ...

}


@Repository

public class BookDao extends BaseDao<Book>{

    @Override

    public void save(){

        ...

    }

    ...

}


@Repository

public class UserDao extends BaseDao<User>{

    @Override

    public void save(){

        ...

    }

    ...

}

  • 然后BookService和UserService都继承了BaseService<T>,并且在继承的时候,确定了泛型的类型。

@Service

public class BookService extends BaseService<Book>{

    ...

}


@Service

public class UserService extends BaseService<User>{

    ...

}


public class BaseService<T>{

    @Autowired

    private BaseDao<T> baseDao;



    public void test(){

        baseDao.save();

    }

    ...

}

流程分析

  • 当在BookService的对象调用test()方法的时候,虽然BaseService没有在容器中,但是BookService在容器中,所以继承了BaseService的BookService会自动为baseDao属性赋值,此时相当于BookService中 有一个 BaseDao<Book> baseDao; 它便会去容器中找一个BaseDao<Book>类型的bean为baseDao赋值。所以将容器中的BookDao赋值给baseDao,当BookService调用test()方法时其实调用的就是bookDao中的save()方法。

@Test

public void test() {



        ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml");

    BookService bookService = ioc.getBean(BookService.class);

        bookService.test();

    }


IOC总结

  • IOC是一个容器,帮我们管理所有的组件

    • 依赖注入:@Autowired:自动注入

    • 某个组件要使用spring提供的更多功能就必须要加入容器中

  • 容器启动,创建所有单实例bean

  • @Autowired自动装配的时候,是从容器中找到这些符合要求的bean


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

推荐阅读更多精彩内容

  • 参考W3C Spring教程 Spring致力于J2EE应用的各种解决方案,而不仅仅专注于某一层解决方案。可以说S...
    王侦阅读 1,169评论 0 6
  • 如下是整篇文章的结构,所需阅读时间大约20min Spring简介 Spring框架由Rod Johnson开发,...
    李序锴阅读 893评论 0 15
  • 前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 单例模式你会几种写法? 工...
    Java3y阅读 2,284评论 1 60
  • 来源:关于Spring IOC (DI-依赖注入)你需要知道的一切作者:zejian Dao层(AccountDa...
    杨井阅读 5,333评论 0 27
  • 十连胜,提前一轮卫冕世界杯冠军,这也是女排的第十个世界冠军,可谓十全十美。女排姑娘们的表现无懈可击,看得让人放心,...
    独自成长阅读 440评论 0 0