本节内容:

  • Spring介绍
  • Spring搭建
  • Spring概念
  • Spring配置讲解
  • 使用注解配置Spring

一、Spring介绍

1. 什么是Spring

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由 RodJohnson 在其著作 Expert One-On-One J2EE Development and Design 中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring 使用基本的 JavaBean 来完成以前只可能由 EJB 完成的事情。然而,Spring 的用途不仅限于服务器端的开发,去开发android也可以。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 的核心是控制反转 (IoC)和面向切面(AOP)。简单来说,Spring 是一个分层的 JavaSE/EEfull-stack(一站式) 轻量级 开源框架。

JavaEE开发分成三层结构:

  • WEB层
  • 业务层
  • 持久层

三层架构中Spring的位置:

Spring是一个大的容器,其中装了很多对象,之前三层架构在运行时,都需要自己来创建对象,比如在web层中需要使用service层中的,需要new。当使用了Spring之后,Spring中已经存好了项目中需要的对象。也就是在三层中,需要对象时不需要在写new了,而是跟Spring要这个对象。

Spring是一站式框架:纯Spring开发一个项目是完全没问题的。正是因为Spring框架性质是属于容器性质的(比如Spring之所以能处理请求,是因为容器中装了能处理请求的框架,所以它在web层能处理请求),容器中装什么对象,就有什么功能。所以可以一站式。

  • WEB层:Spring MVC
  • 业务层:Bean管理:(IoC)
  • 持久层:Spring的JDBC模板。ORM模板用于整合其他的持久层框架。

2. 为什么要学习Spring

  • 方便解耦,简化开发

    • Spring 就是一个大工厂,可以将所有对象创建和依赖关系维护,交给 Spring 管理
  • AOP 编程的支持
    • Spring 提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
  • 声明式事务的支持
    • 只需要通过配置就可以完成对事务的管理,而无需手动编程
  • 方便程序的测试
    • Spring 对 Junit4 支持,可以通过注解方便的测试 Spring 程序
  • 方便集成各种优秀框架
    • Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz 等)的直接支持 降低 JavaEE API 的使用难度
  • Spring 对 JavaEE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等),都提供了封装,使这些 API 应用难度大大降低。

3. Spring 的版本

Spring 3.X 和 Spring4.X

Spring 3.0.2版本:将市面上常见的、支持整合进来的工具类全部进行了收录,这个包里面有很多很多jar包。但是这是Spring坚持“做好事”的最后一个版本,没有任何回报。

以Spring 4.2.4为例:解压压缩包spring-framework-4.2.4.RELEASE-dist.zip

  • docs是Spring的文档,API和开发规范
  • lib下是Spring的jar包和源码包
  • schema下是Spring当中的约束文件

lib目录下的包看起来很多,其实是3个一组:

二、Spring搭建示例

1. 下载导包

Spring官网:http://spring.io/

下载地址: http://repo.springsource.org/libs-release-local/org/springframework/spring

解压好的lib下的jar包不会都用,针对需要选择相应的jar包。

2. 创建web项目,引入Spring的开发包

在 web/WEB_INF/ 目录下创建一个lib目录,把下图中的4个jar包放进lib目录下。

Spring本身也是支持日志的,市面上已经有非常成熟的日志包了,Spring日志系统使用的是Apache开发出来的日志包。所以还需要导入Apache的日志方面的jar包,这部分jar包不在Spring解压后的lib下,得去Apache官方网站下载。把com.springsource.org.apache.commons.logging-1.1.1.jar和com.springsource.org.apache.log4j-1.2.15.jar复制到lib目录下。新版本的Spring应该不需要导入com.springsource.org.apache.log4j-1.2.15.jar,导了也不会错。

点击 File --> Project Structure,进入 Project Structure窗口,点击 Modules --> 选中项目 --> 切换到 Dependencies 选项卡 --> 点击下面的“+”,选择 “JARs or directories...”,选择创建的lib目录。

3. 创建包,编写一个类文件

User.java

  1. package com.wisedu.springDemo;
  2.  
  3. /**
  4. * Created by jkzhao on 12/7/17.
  5. */
  6. public class User {
  7. private String name;
  8. private Integer age;
  9.  
  10. public String getName() {
  11. return name;
  12. }
  13.  
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17.  
  18. public Integer getAge() {
  19. return age;
  20. }
  21.  
  22. public void setAge(Integer age) {
  23. this.age = age;
  24. }
  25.  
  26. @Override
  27. public String toString() {
  28. return "User{" +
  29. "name='" + name + '\'' +
  30. ", age=" + age +
  31. '}';
  32. }
  33. }

  

4. 书写Spring的配置文件,注册对象到Spring容器

对象和框架交流,通过配置文件交流。

Spring的配置文件存放位置任意,放在src目录下。名字也是任意,但是建议叫applicationContext.xml。

选中src,右键选择New --> XML Configuration File --> Spring Config,输入名字applicationContext,点击OK。

默认生成的文件约束是写了一些的。在我们这个例子中,上面默认生成的约束就够用了。

下面开始配置约束,这个user对象要交给Spring容器来管理。

applicationContext.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <!-- 将User对象交给Spring容器管理 -->
  7. <!-- Bean元素:使用该元素描述需要Spring容器管理的对象
  8. name属性:给被管理的对象起个名字。获得对象时根据该名称获得对象
  9. class属性:被管理对象的完整类名
  10. id属性:早年使用的,功能与name属性一模一样,id的规矩:名称不能重复,不能使用特殊字符。所以加了name属性,可以使用特殊字符,名称也可以重复,但是不推荐名称重复。
  11. 结论:尽量使用name属性
  12. -->
  13. <bean name="user" class="com.wisedu.springDemo.User"></bean> <!--属性name的值随意-->
  14. </beans>

 

5. 代码测试

在 src 下创建一个包:com.wisedu.test,然后创建一个类文件testSpringDemo.java:

  1. package com.wisedu.test;
  2.  
  3. import org.junit.Test;
  4. import org.springframework.context.ApplicationContext; //这是一个接口,创建容器对象时需要找其实现类
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. import com.wisedu.springDemo.User;
  7.  
  8. /**
  9. * Created by jkzhao on 12/7/17.
  10. */
  11. public class testSpringDemo {
  12.  
  13. @Test
  14. public void test1(){
  15. //1.创建容器对象(创建Spring的工厂类)
  16. ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); //ClassPathXmlApplicationContext(从类路径下加载xml的Application容器)是org.springframework.context.ApplicationContext的实现类
  17. //2.向容器"要"User对象(通过工厂解析XML获取Bean实例)
  18. User user = (User)ac.getBean("user");
  19. //3.打印User对象
  20. System.out.print(user);
  21. }
  22. }

运行该方法,然后可以发现打印出值了,也就是获取到了User对象。

【注意】:上面在test1方法中,创建容器是使用 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 来创建的,每个项目中只有一个applicationContext对象,不是每个方法中都要创建一下。如何保证只创建一个?

之前学过一个ServletContext域对象,它在一个项目中只有一份,随着程序的启动而创建,随着程序的停止而销毁。这就用到了Listener。监听器中有8个监听器,使用其中一个监听器:ServletContext域创建和销毁的Listener。这样当ServletContext创建时我们可以创建applicationContext对象,当ServletContext销毁时,我们可以销毁applicationContext对象。这样applicationContext就和ServletContext“共生死了”。使用这个监听器还有一个好处,在监听器中可以非常方便地获得事件源,也就意味着我们可以获得ServletContext对象,这个容器被放进了ServletContext域对象中,说通俗点,就是被放进了application域中。Spring已经把这个监听器写好了,我们只需要在web.xml中配置下就可以了。当然还需要导入一个包:spring-web-4.2.4.RELEASE.jar

  1. <listener>
  2. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  3. </listener>

前面在讲到Spring容器时说道,Spring的配置文件位置任意,Spring配置文件名字任意,所以这意味着还需要在web.xml中指明该配置文件的位置及名称。

  1. <!-- 可以让spring容器随着项目的启动而创建,随项目的关闭而销毁-->
  2. <listener>
  3. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  4. </listener>
  5. <!--指定加载Spring配置文件的位置-->
  6. <context-param>
  7. <param-name>contextConfigLocation</param-name> <!--这个key不能改,背下来-->
  8. <param-value>
  9. classpath*:/applicationContext.xml
  10. </param-value>
  11. </context-param>

接着写java代码从application域中获取容器。但是application域中存放东西是键值对存在的,我们得知道键才能取。Spring考虑到这种情况,准备了一个工具方法,把键封装在工具方法中了。

  1. //1.这里以Struts2为例获取ServletContext对象
  2. ServletContext sc = ServletActionContext.getServletContext();
  3. //2.从sc中获得ac容器
  4. WebApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(sc);
  5. //3.从容器中获得需要的对象
  6. ...

三、Spring概念

1. IOC思想和DI技术

(1)IOC (Inverse Of Control):控制反转,将我们创建对象的方式反转了。

以前对象的创建是由开发人员自己维护,包括依赖关系也是自己注入。使用了Spring之后,对象的创建以及依赖关系可以由Spring完成创建以及注入。

(2)DI(Dependency Injection):依赖注入。将必须的属性注入到对象当中,是实现IOC思想的必要条件。

需要有 IOC 的环境,Spring 创建这个类的过程中,Spring 将类的依赖的属性设置进去。

注入方式:

  • set方法注入
  • 构造方法注入
  • 字段注入:不建议。

注入类型:

  • 值类型注入:8大基本数据类型。比如上面示例中的User对象,它里面有name和age两个属性,现在我们希望User对象创建出来后,name="Tom",age=18。这个"Tom"和18可以在配置文件中配置,这样Spring会把我们配置的值自动交给属性。
  • 引用类型注入:将依赖的对象注入

所以实现IOC思想需要DI支持,DI对IOC提供了技术上的支撑。

2. Spring中的工厂(容器)

(1)ApplicationContext

ApplicationContext接口有两个实现类:

  • ClassPathXmlApplicationContext :加载类路径下 Spring 的配置文件
  • FileSystemXmlApplicationContext :从绝对路径上加载本地磁盘下 Spring 的配置文件,基本用不着。

(2)BeanFactory(过时)

BeanFactory是个接口,是Spring框架在初创时创建的第一个接口。像这种初创的接口,功能一般是很少的,针对原始接口的实现类功能较为单一。下面是幅继承关系图。

(3)BeanFactory 和 ApplicationContext 的区别

BeanFactory接口的实现类的容器特点是:每次在获得对象时才会创建对象。比如上面示例中的代码,

  1. User user = (User)ac.getBean("user"); //只有在获取对象时才会创建对象

而ApplicationContext接口实现类的容器特点是:在加载applicationContext.xml(容器启动)时候就会创建容器中配置的所有对象。除此以外,提供更多功能。

总结:在web开发中,使用applicationContext,在硬件资源匮乏的环境使用BeanFactory。

四、Spring配置详解

1. Bean元素的配置

Bean元素:凡是交给Spring容器管理的对象都是由Bean来描述。

  • name属性:给被管理的对象起个名字。获得对象时根据该名称获得对象
  • class属性:被管理对象的完整类名
  • id属性:早年使用的,功能与name属性一模一样,id的规矩:名称不能重复,不能使用特殊字符。所以加了name属性,可以使用特殊字符,名称也可以重复,但是不推荐名称重复。

结论:尽量使用name属性。

2. Spring生成Bean的三种方式(三种对象创建方式)

对象的创建必须经过类的构造函数。

(1)空参构造创建  --最重要

在上面示例中的User对象中加一个无参构造函数

重新创建一个包,把applicationContext.xml复制进该包中,把测试类testSpringDemo.java复制进该包中,并修改该文件中applicationContext.xml的位置。

具体代码如下:

User.java

  1. package com.wisedu.springDemo;
  2.  
  3. /**
  4. * Created by jkzhao on 12/7/17.
  5. */
  6. public class User {
  7. private String name;
  8. private Integer age;
  9.  
  10. public User() {
  11. System.out.println("User对象空构造方法");
  12. }
  13.  
  14. public String getName() {
  15. return name;
  16. }
  17.  
  18. public void setName(String name) {
  19. this.name = name;
  20. }
  21.  
  22. public Integer getAge() {
  23. return age;
  24. }
  25.  
  26. public void setAge(Integer age) {
  27. this.age = age;
  28. }
  29.  
  30. public Car getCar() {
  31. return car;
  32. }
  33.  
  34. public void setCar(Car car) {
  35. this.car = car;
  36. }
  37.  
  38. @Override
  39. public String toString() {
  40. return "User{" +
  41. "name='" + name + '\'' +
  42. ", age=" + age +
  43. '}';
  44. }
  45. }

applicationContext.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <!-- 创建方式1:空参构造创建 -->
  7. <bean name="user" class="com.wisedu.springDemo.User"></bean>
  8.  
  9. </beans>

testSpringDemo.java

  1. package com.wisedu.createObject;
  2.  
  3. import com.wisedu.springDemo.User;
  4. import org.junit.Test;
  5. import org.springframework.context.ApplicationContext;
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;
  7.  
  8. /**
  9. * Created by jkzhao on 12/7/17.
  10. */
  11. public class testSpringDemo {
  12.  
  13. @Test
  14. //创建方式1:空参构造创建对象
  15. public void test1(){
  16. //1.创建容器对象(创建Spring的工厂类)
  17. ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/createObject/applicationContext.xml"); //ClassPathXmlApplicationContext(从类路径下加载xml的Application容器)是org.springframework.context.ApplicationContext的实现类
  18. //2.向容器"要"User对象(通过工厂解析XML获取Bean实例)
  19. User user = (User)ac.getBean("user");
  20.  
  21. //3.打印User对象
  22. System.out.print(user); //true
  23. }
  24.  
  25. }

运行结果:

(2)静态工厂方式  --了解

写一个类,在类中建一个方法,该方法中把user创建出来。调用该方法创建user,然后交给Spring容器来管理,这样就不是Spring来创建对象了,我们希望Spring调用这个方法创建对象

UserFactory.java

  1. package com.wisedu.createObject;
  2.  
  3. import com.wisedu.springDemo.User;
  4.  
  5. /**
  6. * Created by jkzhao on 12/8/17.
  7. */
  8. public class UserFactory {
  9.  
  10. //在该方法中手动把user创建出来。调用该方法创建user,然后交给Spring容器来管理,这样就不是Spring来创建对象了,我们希望Spring调用这个方法创建对象,如何配置呢
  11. public static User createUser(){
  12. System.out.println("静态工厂创建User");
  13.  
  14. return new User();
  15. }
  16.  
  17. }

applicationContext.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <!-- 创建方式1:空参构造创建 -->
  7. <bean name="user" class="com.wisedu.springDemo.User"></bean>
  8.  
  9. <!-- 创建方式2:静态工厂创建
  10. 调用UserFactory的createUser方法来创建名为User2的对象放入容器
  11. -->
  12. <bean name="user2" class="com.wisedu.createObject.UserFactory" factory-method="createUser"></bean>
  13.  
  14. </beans>

testSpringDemo.java

  1. package com.wisedu.createObject;
  2.  
  3. import com.wisedu.springDemo.User;
  4. import org.junit.Test;
  5. import org.springframework.context.ApplicationContext;
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;
  7.  
  8. /**
  9. * Created by jkzhao on 12/7/17.
  10. */
  11. public class testSpringDemo {
  12.  
  13. @Test
  14. //创建方式1:空参构造创建对象
  15. public void test1(){
  16. //1.创建容器对象(创建Spring的工厂类)
  17. ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/createObject/applicationContext.xml"); //ClassPathXmlApplicationContext(从类路径下加载xml的Application容器)是org.springframework.context.ApplicationContext的实现类
  18. //2.向容器"要"User对象(通过工厂解析XML获取Bean实例)
  19. User user = (User)ac.getBean("user");
  20.  
  21. //3.打印User对象
  22. System.out.print(user); //true
  23. }
  24.  
  25. @Test
  26. //创建方式2:静态工厂创建对象
  27. public void test2(){
  28. //1.创建容器对象(创建Spring的工厂类)
  29. ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/createObject/applicationContext.xml"); //ClassPathXmlApplicationContext(从类路径下加载xml的Application容器)是org.springframework.context.ApplicationContext的实现类
  30. //2.向容器"要"User对象(通过工厂解析XML获取Bean实例)
  31. User user = (User)ac.getBean("user2");
  32. //3.打印User对象
  33. System.out.print(user);
  34. }
  35.  
  36. }

(3)实例工厂方式 --了解

  1. public User createUser2(){
  2. System.out.println("实例工厂创建User");
  3.  
  4. return new User();
  5. }

applicationContext.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <!-- 创建方式1:空参构造创建 -->
  7. <bean name="user" class="com.wisedu.springDemo.User"></bean>
  8.  
  9. <!-- 创建方式2:静态工厂创建
  10. 调用UserFactory的createUser方法来创建名为User2的对象放入容器
  11. -->
  12. <bean name="user2" class="com.wisedu.createObject.UserFactory" factory-method="createUser"></bean>
  13.  
  14. <!-- 创建方式3:实例工厂创建
  15. 首先将UserFactory作为普通的bean配置到Spring中,然后再去调用UserFactory对象的createUser2方法
  16. -->
  17. <bean name="user3" factory-bean="userFactory" factory-method="createUser2"></bean>
  18. <bean name="userFactory" class="com.wisedu.createObject.UserFactory"></bean>
  19. </beans>

测试方法:

  1. @Test
  2. //创建方式3:实例工厂创建对象
  3. public void test3(){
  4. //1.创建容器对象(创建Spring的工厂类)
  5. ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/createObject/applicationContext.xml"); //ClassPathXmlApplicationContext(从类路径下加载xml的Application容器)是org.springframework.context.ApplicationContext的实现类
  6. //2.向容器"要"User对象(通过工厂解析XML获取Bean实例)
  7. User user = (User)ac.getBean("user3");
  8. //3.打印User对象
  9. System.out.print(user);
  10. }

3. bean元素的scope属性

scope属性是在bean元素上加的。

  • singleton :默认值,单例对象。被标识为单例的对象在Spring容器中只会存在一份实例。
  • prototype :多例的。被标识为多例的对象每次在获得时才会创建,并且每次创建都是新的对象。单例对象是在容器启动时就创建了。
  • request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中。对象与request生命周期一致。 --基本不用
  • session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中。对象与session生命周期一致。 --基本不用
  • globalSession :WEB 项目中,应用在 Porlet 环境。如果没有 Porlet 环境那么 globalSession 相当于 session。 --基本不用

在未来的开发中,绝大多数scope的取值都是使用默认值,但是Spring与Struts2整合时,action对象要交给Spring来管理,action这个bean得配置为prototype。因为Struts2从架构上来说,每次请求都会创建一个新的action。

4. bean元素的生命周期属性 --了解

通过配置<bean>标签上的 init-method 作为 Bean 的初始化的时候执行的方法,Spring会在对象创建之后立即调用。配置 destroy-method 作为 Bean 的销毁的时候执行的方法。

【注意】:销毁方法想要执行,需要是单例创建的 Bean,而且在工厂关闭的时候,Bean 才会被销毁.

5. Spring的分模块配置文件

实际开发中,可能会把Sprign的配置写到多个文件中,这时可以在Spring主配置文件中引入其他Spring配置文件。

  1. <!-- 导入其他Spring配置文件-->
  2. <import resource="applicationContext.xml" />

6. Spring中的Bean的属性注入

(1)set方法注入属性   --最重要

applicationContext.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <!--set方式注入:值类型和引用类型-->
  7. <bean name="user" class="com.wisedu.springDemo.User">
  8. <!--为User对象中名为name的属性注入tom作为值-->
  9. <property name="name" value="tom"></property>
  10. <property name="age" value="18"></property>
  11. <!--为car属性注入下方配置的car对象-->
  12. <property name="car" ref="car"></property>
  13. </bean>
  14.  
  15. <!--必须将car对象配置到容器中-->
  16. <bean name="car" class="com.wisedu.springDemo.Car">
  17. <property name="name" value="兰博基尼"></property>
  18. <property name="color" value="黄色"></property>
  19. </bean>
  20.  
  21. </beans>

User.java

  1. package com.wisedu.springDemo;
  2.  
  3. /**
  4. * Created by jkzhao on 12/7/17.
  5. */
  6. public class User {
  7. private String name;
  8. private Integer age;
  9. private Car car;
  10.  
  11. public User() {
  12. System.out.println("User对象空构造方法");
  13. }
  14.  
  15. public String getName() {
  16. return name;
  17. }
  18.  
  19. public void setName(String name) {
  20. this.name = name;
  21. }
  22.  
  23. public Integer getAge() {
  24. return age;
  25. }
  26.  
  27. public void setAge(Integer age) {
  28. this.age = age;
  29. }
  30.  
  31. public Car getCar() {
  32. return car;
  33. }
  34.  
  35. public void setCar(Car car) {
  36. this.car = car;
  37. }
  38.  
  39. @Override
  40. public String toString() {
  41. return "User{" +
  42. "name='" + name + '\'' +
  43. ", age=" + age +
  44. ", car=" + car +
  45. '}';
  46. }
  47. }

Car.java

  1. package com.wisedu.springDemo;
  2.  
  3. /**
  4. * Created by jkzhao on 12/8/17.
  5. */
  6. public class Car {
  7. private String name;
  8. private String color;
  9.  
  10. public String getName() {
  11. return name;
  12. }
  13.  
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17.  
  18. public String getColor() {
  19. return color;
  20. }
  21.  
  22. public void setColor(String color) {
  23. this.color = color;
  24. }
  25.  
  26. @Override
  27. public String toString() {
  28. return "Car{" +
  29. "name='" + name + '\'' +
  30. ", color='" + color + '\'' +
  31. '}';
  32. }
  33. }

测试方法:

  1. @Test
  2. public void test1(){
  3. //1.创建容器对象(创建Spring的工厂类)
  4. ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/injection/applicationContext.xml"); //ClassPathXmlApplicationContext(从类路径下加载xml的Application容器)是org.springframework.context.ApplicationContext的实现类
  5. //2.向容器"要"User对象(通过工厂解析XML获取Bean实例)
  6. User user = (User)ac.getBean("user");
  7. //3.打印User对象
  8. System.out.println(user);
  9. }

运行结果:

(2)构造函数注入属性  --重要

前提:类中得有带有参数的构造函数。

在上面的User.java中添加拥有两个参数的构造方法:

  1. public User(String name, Car car) {
  2. System.out.println("User(String name, Car car)");
  3. this.name = name;
  4. this.car = car;
  5. }

在applicationContext.xml文件中添加配置:

  1. <!-- ============================================== -->
  2. <!-- 构造函数注入 -->
  3. <bean name="user2" class="com.wisedu.springDemo.User">
  4. <constructor-arg name="name" value="jerry"></constructor-arg>
  5. <constructor-arg name="car" ref="car"></constructor-arg>
  6. </bean>

测试方法:

  1. @Test
  2. public void test2(){
  3. //1.创建容器对象(创建Spring的工厂类)
  4. ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/injection/applicationContext.xml"); //ClassPathXmlApplicationContext(从类路径下加载xml的Application容器)是org.springframework.context.ApplicationContext的实现类
  5. //2.向容器"要"User对象(通过工厂解析XML获取Bean实例)
  6. User user = (User)ac.getBean("user2");
  7. //3.打印User对象
  8. System.out.println(user);
  9.  
  10. }

运行结果:

但是假设我们User类中有多个构造方法,里面参数位置不一样,代表实际业务中不同的逻辑,比如:

  1. public User(String name, Car car) {
  2. System.out.println("User(String name, Car car)");
  3. this.name = name;
  4. this.car = car;
  5. }
  6.  
  7. public User(Car car, String name) {
  8. System.out.println("User(Car car, String name)");
  9. this.name = name;
  10. this.car = car;
  11. }

我们如何在配置文件中指定走哪个构造方法呢?需要index属性,index=0表示该属性是构造方法中的第一个参数,index=1表示该属性是构造方法中的第二个参数。

  1. <!-- ============================================== -->
  2. <!-- 构造函数注入 -->
  3. <bean name="user2" class="com.wisedu.springDemo.User">
  4. <constructor-arg name="name" value="jerry" index="0"></constructor-arg>
  5. <constructor-arg name="car" ref="car" index="1"></constructor-arg>
  6. </bean>

还有一种情况,构造方法是这样的,代表另一种业务。

  1. public User(String name, Car car) { //业务1
  2. System.out.println("User(String name, Car car)");
  3. this.name = name;
  4. this.car = car;
  5. }
  6.  
  7. public User(Car car, String name) { //业务2
  8. System.out.println("User(Car car, String name)");
  9. this.name = name;
  10. this.car = car;
  11. }
  12.  
  13. public User(Integer name, Car car) { //业务3
  14. System.out.println("User(Integer name, Car car)");
  15. this.name = name + "";
  16. this.car = car;
  17. }

配置:

  1. <!-- ============================================== -->
  2. <!-- 构造函数注入 -->
  3. <bean name="user2" class="com.wisedu.springDemo.User">
  4. <!--name属性:构造函数的参数名-->
  5. <!--index属性:构造函数的参数索引-->
  6. <!--type属性:构造函数的参数的类型-->
  7. <constructor-arg name="name" value="999" index="0" type="java.lang.Integer"></constructor-arg>
  8. <constructor-arg name="car" ref="car" index="1"></constructor-arg>
  9. </bean>

(3)p名称空间注入属性  --了解

需要引入p名称空间。

  1. <!-- ============================================== -->
  2. <!-- p名称空间注入,本质走的还是set方法,只不过这种写法是Spring新发明了,简化了set的写法。 -->
  3. <!--1.需要p名称空间:xmlns:p="http://www.springframework.org/schema/p"
  4. 2.使用p:属性注入
  5. 值类型:p:属性名="值"
  6. 引用类型:p:属性名-ref="bean名称"
  7. -->
  8. <bean name="user3" class="com.wisedu.springDemo.User" p:name="jack" p:age="20" p:car-ref="car"></bean>

  

(4)spel注入属性  --了解

  1. <!-- ============================================== -->
  2. <!-- spel注入:Spring Expression Language,Spring表达式语言,类似el、jstl表达式-->
  3. <bean name="user4" class="com.wisedu.springDemo.User">
  4. <property name="name" value="#{user.name}"></property> <!--找name="user"的对象,找它的属性name-->
  5. <property name="age" value="#{user3.age}"></property>
  6. <property name="car" ref="car"></property> <!--引用类型不允许使用spel表达式-->
  7. </bean>

(5)复杂类型的注入

前面讲的注入类型要么就是值,要么就是对象。如果遇到数组、Map、List或properties,该如何注入?直接使用set方式注入这几种复杂类型。

CollectionBean.java

  1. package com.wisedu.injection;
  2.  
  3. import java.util.*;
  4.  
  5. /**
  6. * Created by jkzhao on 12/8/17.
  7. */
  8. public class CollectionBean {
  9. private Object[] arr;
  10. private List list; //list和set的注入方式一样
  11. private Map map;
  12. private Properties prop; //Properties就是个map
  13.  
  14. public Object[] getArr() {
  15. return arr;
  16. }
  17.  
  18. public void setArr(Object[] arr) {
  19. this.arr = arr;
  20. }
  21.  
  22. public List getList() {
  23. return list;
  24. }
  25.  
  26. public void setList(List list) {
  27. this.list = list;
  28. }
  29.  
  30. public Map getMap() {
  31. return map;
  32. }
  33.  
  34. public void setMap(Map map) {
  35. this.map = map;
  36. }
  37.  
  38. public Properties getProp() {
  39. return prop;
  40. }
  41.  
  42. public void setProp(Properties prop) {
  43. this.prop = prop;
  44. }
  45.  
  46. @Override
  47. public String toString() {
  48. return "CollectionBean{" +
  49. "arr=" + Arrays.toString(arr) +
  50. ", list=" + list +
  51. ", map=" + map +
  52. ", prop=" + prop +
  53. '}';
  54. }
  55. }

applicationContext.xml

  1. <!--复杂类型注入-->
  2. <bean name="cb" class="com.wisedu.injection.CollectionBean">
  3. <!--如果数组中只准备注入一个值(对象),直接使用value或ref即可。比如下面的配置直接往数组中注入了一个值tom-->
  4. <!--<property name="arr" value="tom"></property>-->
  5. <!--如果数组中准备注入多个元素-->
  6. <property name="arr">
  7. <array>
  8. <value>tom</value>
  9. <value>jerry</value>
  10. <ref bean="user4"/>
  11. </array>
  12. </property>
  13.  
  14. <!--如果List中只准备注入一个值(对象),直接使用value或ref即可。-->
  15. <!--<property name="list" value="jack"></property>-->
  16. <!--如果list中准备注入多个元素-->
  17. <property name="list">
  18. <list>
  19. <value>jack</value>
  20. <value>rose</value>
  21. <ref bean="user3"/>
  22. </list>
  23. </property>
  24.  
  25. <!--map类型注入-->
  26. <property name="map">
  27. <map>
  28. <entry key="url" value="jdbc:mysql://crm"></entry>
  29. <entry key="car" value-ref="car"></entry>
  30. <entry key-ref="user3" value-ref="user4"></entry>
  31. </map>
  32. </property>
  33.  
  34. <!--Properties类型注入-->
  35. <property name="prop">
  36. <props>
  37. <prop key="driverClass">com.jdbc.mysql.Driver</prop>
  38. <prop key="userName">root</prop>
  39. <prop key="password">123456</prop>
  40. </props>
  41. </property>
  42.  
  43. </bean>

测试方法:

  1. @Test
  2. public void test5(){
  3. //1.创建容器对象(创建Spring的工厂类)
  4. ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/injection/applicationContext.xml"); //ClassPathXmlApplicationContext(从类路径下加载xml的Application容器)是org.springframework.context.ApplicationContext的实现类
  5. //2.向容器"要"User对象(通过工厂解析XML获取Bean实例)
  6. CollectionBean cb = (CollectionBean)ac.getBean("cb");
  7. //3.打印User对象
  8. System.out.println(cb);
  9.  
  10. }

五、使用注解配置Spring(代替xml配置)

Hibernate、Struts2、Spring都支持注解方式配置。注解是JDK1.5开始引入的,这三大框架都是在JDK1.5以前出来的。但是在开发中很少使用注解来配置Hibernate和Struts2。

1. 注解示例

新建一个包,com.wisedu.annotation。

(1)Spring 4.2.4使用注解还需要导入一个包

spring-aop-4.2.4.RELEASE.jar   老版本不需要。

(2)为主配置文件引入新的命名空间(约束)

在默认生成的applicationContext.xml文件中添加配置

  1. xmlns:context="http://www.springframework.org/schema/context"

在 xsi:schemaLocation= 后面添加如下配置:

  1. http://www.springframework.org/schema/context
  2. http://www.springframework.org/schema/context/spring-context-3.0.xsd

(3)在主配置文件中开启使用注解代理配置文件(打开使用注解的开发)

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  6.  
  7. <!--component可以理解为对象,我们把对象放进容器中,对Spring来说就是把组件放进来了-->
  8. <!--base-package: 扫描你给的这个包下所有的类,看上面有没有注解。扫描到注解,会启动注解配置。
  9. 如果这个包下面还有子包的话,还会扫描子包下的类
  10. -->
  11. <context:component-scan base-package="com.wisedu"></context:component-scan>
  12. </beans>

(4)在类中使用注解完成配置

User.java

  1. package com.wisedu.annotation;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.beans.factory.annotation.Qualifier;
  5. import org.springframework.beans.factory.annotation.Value;
  6. import org.springframework.context.annotation.Scope;
  7. import org.springframework.stereotype.Component;
  8.  
  9. import javax.annotation.PostConstruct;
  10. import javax.annotation.PreDestroy;
  11. import javax.annotation.Resource;
  12.  
  13. /**
  14. * Created by jkzhao on 12/7/17.
  15. */
  16. //@Component //组件
  17. //<bean name="user" class="com.wisedu.annotation.User" />
  18. @Component("user")
  19. public class User {
  20.  
  21. private String name;
  22. private Integer age;
  23. private Car car;
  24.  
  25. public String getName() {
  26. return name;
  27. }
  28.  
  29. public void setName(String name) {
  30. this.name = name;
  31. }
  32.  
  33. public Integer getAge() {
  34. return age;
  35. }
  36.  
  37. public void setAge(Integer age) {
  38. this.age = age;
  39. }
  40.  
  41. public Car getCar() {
  42. return car;
  43. }
  44.  
  45. public void setCar(Car car) {
  46. this.car = car;
  47. }
  48.  
  49. @Override
  50. public String toString() {
  51. return "User{" +
  52. "name='" + name + '\'' +
  53. ", age=" + age +
  54. ", car=" + car +
  55. '}';
  56. }
  57. }

其中,@Component()是Spring在注册Bean的一个早期注解,后来又出现了这么几个注解:@Service()、@Controller、@Repository()

一开始只有@Component(),但是后来使用者向Spring反馈,在注册项目中所有对象的时候,都有这同一个注解,这样很难区分这个对象属于哪一层,所以又增加3个注解。这3个注解和@Component()没有任何区别,但是这3个注解通过看名字,就知道注册的对象属于哪一层。

  • @Service():注册service层对象
  • @Controller:注册web层对象
  • @Repository():注册Dao层对象

(5)测试

test.java

  1. package com.wisedu.annotation;
  2.  
  3. import com.wisedu.annotation.User;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.context.ApplicationContext;
  7. import org.springframework.context.support.ClassPathXmlApplicationContext;
  8. import org.springframework.test.context.ContextConfiguration;
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  10.  
  11. import javax.annotation.Resource;
  12.  
  13. /**
  14. * Created by jkzhao on 12/7/17.
  15. */
  16. @RunWith(SpringJUnit4ClassRunner.class) //帮我们创建容器
  17. @ContextConfiguration("classpath:com/wisedu/annotation/applicationContext.xml") //指定创建容器时使用哪个文件
  18. //@ContextConfiguration(locations = "classpath:com/wisedu/annotation/applicationContext.xml")
  19. public class test {
  20. //将名为user的对象注入到u变量中
  21. @Resource(name = "user")
  22. private User u;
  23.  
  24. @Test
  25. public void test3(){
  26. System.out.print(u);
  27.  
  28. }
  29.  
  30. @Test
  31. public void test1(){
  32. //1.创建容器对象(创建Spring的工厂类)
  33. ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/annotation/applicationContext.xml"); //ClassPathXmlApplicationContext(从类路径下加载xml的Application容器)是org.springframework.context.ApplicationContext的实现类
  34. //2.向容器"要"User对象(通过工厂解析XML获取Bean实例)
  35. User user = (User)ac.getBean("user");
  36. //3.打印User对象
  37. System.out.print(user);
  38.  
  39. }
  40.  
  41. }

  

2. 注解形式下对象的作用范围

@Scope(scopeName = "prototype") //默认是单例的

  1. package com.wisedu.annotation;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.beans.factory.annotation.Qualifier;
  5. import org.springframework.beans.factory.annotation.Value;
  6. import org.springframework.context.annotation.Scope;
  7. import org.springframework.stereotype.Component;
  8.  
  9. import javax.annotation.PostConstruct;
  10. import javax.annotation.PreDestroy;
  11. import javax.annotation.Resource;
  12.  
  13. /**
  14. * Created by jkzhao on 12/7/17.
  15. */
  16. //@Component //组件
  17. //<bean name="user" class="com.wisedu.annotation.User" />
  18. @Component("user")
  19. @Scope(scopeName = "prototype") //默认是单例的
  20. public class User {
  21. private String name;
  22. private Integer age;
  23. private Car car;
  24.  
  25. public String getName() {
  26. return name;
  27. }
  28.  
  29. public void setName(String name) {
  30. this.name = name;
  31. }
  32.  
  33. public Integer getAge() {
  34. return age;
  35. }
  36.  
  37. public void setAge(Integer age) {
  38. this.age = age;
  39. }
  40.  
  41. public Car getCar() {
  42. return car;
  43. }
  44.  
  45. public void setCar(Car car) {
  46. this.car = car;
  47. }
  48.  
  49. @Override
  50. public String toString() {
  51. return "User{" +
  52. "name='" + name + '\'' +
  53. ", age=" + age +
  54. ", car=" + car +
  55. '}';
  56. }
  57. }

测试方法:

  1. @Test
  2. public void test2(){
  3. //1.创建容器对象(创建Spring的工厂类)
  4. ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/annotation/applicationContext.xml"); //ClassPathXmlApplicationContext(从类路径下加载xml的Application容器)是org.springframework.context.ApplicationContext的实现类
  5. //2.向容器"要"User对象(通过工厂解析XML获取Bean实例)
  6. User user = (User)ac.getBean("user");
  7. User user2 = (User)ac.getBean("user");
  8. User user3 = (User)ac.getBean("user");
  9. //3.打印User对象
  10. System.out.print(user==user2);
  11.  
  12. }

  

3. 属性的注入

(1)值赋值

在成员变量上面加注释@Value(),或者把这个注释放到这个成员变量的set方法上。

User.java

  1. package com.wisedu.annotation;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.beans.factory.annotation.Qualifier;
  5. import org.springframework.beans.factory.annotation.Value;
  6. import org.springframework.context.annotation.Scope;
  7. import org.springframework.stereotype.Component;
  8.  
  9. import javax.annotation.PostConstruct;
  10. import javax.annotation.PreDestroy;
  11. import javax.annotation.Resource;
  12.  
  13. /**
  14. * Created by jkzhao on 12/7/17.
  15. */
  16. //@Component //组件
  17. //<bean name="user" class="com.wisedu.annotation.User" />
  18. @Component("user")
  19. @Scope(scopeName = "prototype") //默认是单例的
  20. public class User {
  21. @Value("tom")
  22. private String name;
  23. private Integer age;
  24.  
  25. private Car car;
  26.  
  27. public String getName() {
  28. return name;
  29. }
  30.  
  31. public void setName(String name) {
  32. this.name = name;
  33. }
  34.  
  35. public Integer getAge() {
  36. return age;
  37. }
  38.  
  39. @Value(value = "18")
  40. public void setAge(Integer age) {
  41. this.age = age;
  42. }
  43.  
  44. public Car getCar() {
  45. return car;
  46. }
  47.  
  48. public void setCar(Car car) {
  49. this.car = car;
  50. }
  51.  
  52. @Override
  53. public String toString() {
  54. return "User{" +
  55. "name='" + name + '\'' +
  56. ", age=" + age +
  57. ", car=" + car +
  58. '}';
  59. }
  60. }

这两种的区别:

加在成员变量上,Spring在给这个对象赋值的时候,通过反射的Field赋值。而放在成员的set方法上,走的set方法赋值的(推荐使用)。

虽然结果是一样的,但是放在成员变量上破坏了对象的封装性。本来这个属性私有,就是为了封装,提供get和set方法操作,加在成员变量上就是Spring直接去操作对象了。

所以在set方法上加是推荐上,但是在成员变量上加很清晰,方便,在set方法上加很别扭,这就很矛盾。实际使用上两种都可以。

另外,上面的示例中:@Value(value="18")和@Value("18")是一样的,这是一个结论(直接记住):如果注解中的属性如果只有一个需要赋值,并且这个属性名是value的话,写的时候可以忽略属性的键,也就是忽略"value"。包括前面写的@Component("user"),没写键的,都是给value赋值的。

(2)引用类型赋值

首先你必须把赋值的对象给注册到容器中,比如上面示例中的car。

多种方式实现对象赋值:

第一种:

User.java代码片段:

  1. @Component("user")
  2. @Scope(scopeName = "prototype") //默认是单例的
  3. public class User {
  4. @Value("tom")
  5. private String name;
  6. private Integer age;
  7. @Autowired //自动装配。根据类型来检测扫描容器当中符合这个属性类型的对象,如果检测到了,找到这个对象,赋值给这个属性
  8. @Qualifier("car2")
  9. private Car car;
      ...

其中,Car.java代码片段:

  1. @Component("car")
  2. public class Car {
  3. @Value("兰博基尼")
  4. private String name;
  5. @Value("屎黄色")
  6. private String color;
  7. ...

运行结果:

这种注入引用类型有个缺陷,假如我把这个Car注册到好几遍这个容器当中,假如在容器中有3辆车。比如这个在applicationContext.xml中在配置辆车。

  1. <bean name="car2" class="com.wisedu.annotation.Car">
  2. <property name="name" value="特斯拉"></property>
  3. <property name="color" value="蓝色"></property>
  4. </bean>

这样Spring中就有两辆车了。这样我们无法控制具体将哪辆车注入Car属性。这个时候我们可以给 @Autowired 加个辅助注解,

  1. @Autowired
  2. @Qualifier("car2")
  3. private Car car;

再次运行:

第二种:当引用对象有多个的时候,需要把该对象注入给某属性时,不建议使用上面两个注解,有个注解不是自动装配,直接“指名道姓”,叫@Resource(name = "car2")

  1. //@Autowired //自动装配。根据类型来检测扫描容器当中符合这个属性类型的对象,如果检测到了,找到这个对象,赋值给这个属性
  2. //@Qualifier("car2")
  3. @Resource(name = "car2") //手动注入,指定注入哪个名称的对象
  4. private Car car;

4. 初始化和销毁方法

User.java代码片段:

  1. @PostConstruct //在对象被创建后调用,类似于之前学习的init-method
  2. public void init(){
  3. System.out.println("初始化方法");
  4. }
  5. @PreDestroy //在对象销毁之前调用,类似于之前学习的destory-method
  6. public void destory(){
  7. System.out.println("销毁方法");
  8. }

【注意】:如果想执行销毁方法,必须将User对象改为单例的。

Spring的Bean管理方式的比较:

XML和注解:

  • XML:结构清晰
  • 注解:开发方便(属性注入)

实际开发中还有一种 XML 和注解整合开发:

  • Bean 有 XML 配置,但是使用的属性使用注解注入

Spring介绍及配置(XML文件配置和注解配置)的更多相关文章

  1. Java Web的web.xml文件作用及基本配置(转)

    其实web.xml就是asp.net的web.config一个道理. 说明: 一个web中完全可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的. web.xml文件是用来 ...

  2. Spring(二)--FactoryBean、bean的后置处理器、数据库连接池、引用外部文件、使用注解配置bean等

    实验1:配置通过静态工厂方法创建的bean  [通过静态方法提供实例对象,工厂类本身不需要实例化!] 1.创建静态工厂类 public class StaticFactory { private st ...

  3. 【转载】Java Web的web.xml文件作用及基本配置

    其实web.xml就是asp.net的web.config一个道理. 说明: 一个web中完全可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的. web.xml文件是用来 ...

  4. 项目配置 xml文件时 报错提示(The reference to entity "useSSL" must end with the ';' delimiter.)

    这次在配置xml文件时,出现错误提示( The reference to entity “useSSL” must end with the ‘;’ delimiter.) 报错行为 <prop ...

  5. 【报错】spring整合activeMQ,pom.xml文件缺架包,启动报错:Caused by: java.lang.ClassNotFoundException: org.apache.xbean.spring.context.v2.XBeanNamespaceHandler

    spring版本:4.3.13 ActiveMq版本:5.15 ======================================================== spring整合act ...

  6. mybatis,Spring等工具对xml文件正确性的验证

    我们知道mybatis或者spring都是使用xml文件作为配置文件,配置文件的格式都是定义在叫做.dtd或者.xsd文件中的,当工具在解析用户自己定义的xml文件的时候,如何才能知道用户自定义的文件 ...

  7. Spring整合Hibernate的XML文件配置,以及web.xml文件配置

    利用Spring整合Hibernate时的XML文件配置 applicationContext.xml <?xml version="1.0" encoding=" ...

  8. JAVA Spring 简单的配置和操作 ( 创建实体类, 配置XML文件, 调试 )

    < 1 > 实体类 Person package java_spring.modle; /** * 一个实体类( Person ) */ public class Person { pri ...

  9. Struts2 学习笔记——struts.xml文件之Bean的配置

    Struts2的大部分核心组件不是以硬编码的形式写在代码中,而是通过自身的IoC容器来管理的. Struts2以可配置的形式来管理核心组件,所以开发者可以很容易的扩展框架的核心组件.当开发者需要扩展或 ...

随机推荐

  1. 2017易观OLAP算法大赛

      大赛简介   目前互联网领域有很多公司都在做APP领域的“用户行为分析”产品,与Web时代的行为分析相类似,其目的都是帮助公司的运营.产品等部门更好地优化自家产品,比如查看日活和月活,查看渠道来源 ...

  2. Head内常用标签

    一.标签分类 1.1 自闭和标签 自闭和标签只有开头没有结尾,自动闭合: <meta> 标签 <link> 标签 1.2主动闭合标签 有开头也有结尾,是主动闭合的,称为主动闭合 ...

  3. Python【yagmail】模块发邮件

    #步骤一:import yagmail #步骤二:实例化一个发邮件的对象username = '553637138@qq.com' #邮箱账号pwd='sa2008' #授权码mail = yagma ...

  4. 抓包工具Charles

    Charles Charles可以在windows,linux,mac各种操作系统上安装使用,它是java编写一款非免费工具:而fiddler只能在windows系统上使用 Charles抓包前,要确 ...

  5. NO.6LINUX基本命令

    1.练习1 ) 将用户信息数据库文件和组信息数据库文件纵向合并为一个文件/1.txt(覆盖) cd / cat /etc/passwd /etc/group>1.txt 2) 将用户信息数据库文 ...

  6. P2054 [AHOI2005]洗牌

    P2054 [AHOI2005]洗牌 题目描述 为了表彰小联为Samuel星球的探险所做出的贡献,小联被邀请参加Samuel星球近距离载人探险活动. 由于Samuel星球相当遥远,科学家们要在飞船中度 ...

  7. Swiper点击后自动轮播停止情况

    用户操作swiper之后,是否禁止autoplay.默认为true:停止. 如果设置为false,用户操作swiper之后自动切换不会停止,每次都会重新启动autoplay. 操作包括触碰,拖动,点击 ...

  8. TPL概要

    ReaderWriterLockSlim.读写锁,允许多个线程同时获取读锁,但同一时间只允许一个线程获得写锁,因此也称作共享-独占锁.只有等到对象被写入锁占用的时候,才会阻塞 Barrier .它允许 ...

  9. UC手机浏览器(U3内核)相关文档整理

    Note:绝大多数API在IOS版下不支持,使用前请自行测试. UC官方的开发者中心:http://www.uc.cn/business/developer.shtml U3内核定制<meta& ...

  10. JavaScript 运行机制之执行顺序详解

    JavaScript是一种描述型脚本语言,它不同于 Java 或 C# 等编译性语言,它不需要进行编译成中间语言,而是由浏览器进行动态地解析与执行.如果你不能理解 JavaScript 语言的运行机制 ...