Spring概述,IOC,DI

Spring概述及体系介绍

Spring概述

①Spring是一个开源框架

②Spring为简化企业级开发而生,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得非常的优雅和简洁,有效的降低代码的耦合度,极大的方便项目的后期维护、升级和扩展。

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

④Spring的优良特性

[1]非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API

[2]控制反转:IOC——Inversion of Control,指的是将对象的创建权交给Spring去创建。使用Spring之前,对象的创建都是由我们自己在代码中new创建。而使用Spring之后。对象的创建都是由给了Spring框架。

[3]依赖注入:DI——Dependency Injection,是指依赖的对象不需要手动调用setXX方法去设置,而是通过配置赋值。

[4]面向切面编程:Aspect Oriented Programming——AOP

[5]容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期

[6]组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。

[7]一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)

Spring体系介绍


(1)核心容器:包括Core、Beans、Context、EL模块

Core模块:封装了框架依赖的最底层部分,包括资源访问、类型转换及一些常用工具类。

Beans模块:提供了框架的基础部分,包括反转控制和依赖注入。其中Bean Factory是容器核心,本质是“工厂设计模式”的实现,而且无需编程实现“单例设计模式”,单例完全由容器控制,而且提倡面向接口编程,而非面向实现编程;所有应用程序对象及对象间关系由框架管理,从而真正把你从程序逻辑中把维护对象之间的依赖关系提取出来,所有这些依赖关系都由BeanFactory来维护。

Context模块:以Core和Beans为基础,集成Beans模块功能并添加资源绑定、数据验证、国际化、Java EE支持、容器生命周期、事件传播等;核心接口是ApplicationContext。

EL模块:提供强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从Spring 容器获取Bean,它也支持列表投影、选择和一般的列表聚合等。

(2)AOP、Aspects模块

AOP模块:Spring AOP模块提供了符合 AOP Alliance规范的面向方面的编程(aspect-oriented programming)实现,提供比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态的把这些功能添加到需要的代码中;这样各专其职,降低业务逻辑和通用功能的耦合。

Aspects模块:提供了对AspectJ的集成,AspectJ提供了比Spring ASP更强大的功能。

数据访问/集成模块:该模块包括了JDBC、ORM、OXM、JMS和事务管理。

事务模块:该模块用于Spring管理事务,只要是Spring管理对象都能得到Spring管理事务的好处,无需在代码中进行事务控制了,而且支持编程和声明性的事务管理。

JDBC模块:提供了一个JBDC的样例模板,使用这些模板能消除传统冗长的JDBC编码还有必须的事务控制,而且能享受到Spring管理事务的好处。

ORM模块:提供与流行的“对象-关系”映射框架的无缝集成,包括Hibernate、JPA、MyBatis等。而且可以使用Spring事务管理,无需额外控制事务。

OXM模块:提供了一个对Object/XML映射实现,将java对象映射成XML数据,或者将XML数据映射成java对象,Object/XML映射实现包括JAXB、Castor、XMLBeans和XStream。

JMS模块:用于JMS(Java Messaging Service),提供一套 “消息生产者、消息消费者”模板用于更加简单的使用JMS,JMS用于用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。

Web/Remoting模块:Web/Remoting模块包含了Web、Web-Servlet、Web-Struts、Web-Porlet模块。

Web模块:提供了基础的web功能。例如多文件上传、集成IoC容器、远程过程访问(RMI、Hessian、Burlap)以及Web Service支持,并提供一个RestTemplate类来提供方便的Restful services访问。

Web-Servlet模块:提供了一个Spring MVC Web框架实现。Spring MVC框架提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等及一套非常易用的JSP标签,完全无缝与Spring其他技术协作。

Web-Struts模块:提供了与Struts无缝集成,Struts1.x 和Struts2.x都支持

Test模块: Spring支持Junit和TestNG测试框架,而且还额外提供了一些基于Spring的测试功能,比如在测试Web框架时,模拟Http请求的功能。

Spring安装配置

创建工程

添加maven依赖

<dependencies>
    <!-- Spring IOC最小依赖是beans、context,我们引入context依赖,maven会自动将beans依赖一并引入 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>
</dependencies>

快速开始

1.编写配置文件

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
    <context:component-scan base-package="com.lanou3g.spring" />

</beans>

2.依赖注入(DI)


/**
 * Service
 */
public interface StudentService {
    List<Student> queryStudents();
}

public class StudentServiceImpl implements StudentService {

    // 通过Spring DI自动注入
    @Autowired
    private StudentDao studentDao;

    @Override
    public List<Student> queryStudents() {
        return studentDao.queryStudents();
    }
}

/**
 * dao
 */
public interface StudentDao {
    List<Student> queryStudents();
}

public class StudentDaoImpl implements StudentDao {
    @Override
    public List<Student> queryStudents() {
        return new ArrayList<>();
    }
}

/**
 * 实体类
 */
@Setter
@Getter
@Component
public class Student {
    private Integer id;
    private String sname;
    private Integer age;
    private String gender;
    private String nickName;
}

3.加载配置文件,获取SpringContext管理的Bean(控制反转IOC)

public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student stu = ctx.getBean(Student.class);
        System.out.println(stu);
    }

IOC

ApplicationContext实现类

在Spring中,构成应用程序主干并由Spring IOC容器管理的对象称为bean。 bean是一个由Spring IOC容器实例化,组装和管理的对象。ApplicationContext代表了Spring IOC容器,通过它我们可以实现对Spring IOC容器的所有操作:实例化、配置、组装bean。 通常我们在开发中直接用到的是ApplicatoinContext接口和它的各种实现类。

ClassPathXmlApplicationContext

用于加载类路径下的spring配置文件,通常用于控制台程序

使用方法:

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentService ss = ctx.getBean(StudentService.class);
System.out.println(ss);

AnnotationConfigApplicationContext

用于初始化通过注解方式配置的ioc容器

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
  
  	public static void main(String[] args) {
      ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
      MyService myService = ctx.getBean(MyService.class);
     System.out.println(myService);
		}
}

Application初始化路径

路径前缀

//	前缀classpath:表示的是项目的classpath下相对路径   
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");

路径中的通配符

//	使用通配符加载所有符合要求的文件   
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath*:applicationContext.xml");

通过xml方式配置管理bean

优点:对代码没有任何侵入性, 改了配置不需要重新编译、打包

缺点:配置相比注解的方式要繁琐很多,工程量比较大

public interface MessageDao {
    List<String> queryAllMessageTitle();
}

public class MessageServiceImpl {

    MessageDao messageDao;

    public String choiceOneMessageTitle() {
        List<String> messageList = messageDao.queryAllMessageTitle();
        int idx = new Random().nextInt(messageList.size());
        return  messageList.get(idx);
    }

    public MessageDao getMessageDao() {
        return messageDao;
    }

    public void setMessageDao(MessageDao messageDao) {
        this.messageDao = messageDao;
    }
}

<bean id="messageService" class="com.lanou3g.spring.service.MessageServiceImpl">
        <property name="messageDao" ref="md" />
    </bean>
  public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testIOCQuicklyStart(ctx);
    }

private void testIOCQuicklyStart(ApplicationContext ctx) {
        // message相关的bean是通过xml方式配置
        MessageServiceImpl messageService = ctx.getBean("messageService", MessageServiceImpl.class);
        String title = messageService.choiceOneMessageTitle();
        System.out.println(title);
    }

通过注解方式管理bean

优点:配置简单。由于Java类中已经包含很上下文信息,所有在Java类上直接加注解可以省略很多属性。

缺点:对代码有侵入性,如果改了是基于注解的配置信息改变了,需要重新编译、打包

public interface Fruit {
    void eatFruit();
}

// 用@Configuration注解的类就相当于是一个xml的配置文件
@Configuration
@Import(MyConf.class)   // <import resource="" />
@ImportResource("applicationContext.xml")
//@ComponentScan(basePackages = "com.lanou3g.spring")
public class App {

    @Autowired
    @Qualifier("ap") //这里写的apple对应的是bean的id或者name
    private Fruit fruit;

    public void testFruit() {
        fruit.eatFruit();
    }

    public Fruit getFruit() {
        return fruit;
    }

    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }
}

 public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testIOCQuicklyStart(ctx);
    }

private void testIOCQuicklyStart(ApplicationContext ctx) {
        //app相关的bean是通过注解方式配置
        App app = ctx.getBean("app", App.class);
        app.testFruit();
    }

xml和注解方式混合使用

Spring提供@Configuration@Bean等注解的方式并不是为了要完全取代xml配置方式, 而是要看使用场合,比如数据源的配置, 就不适合通过注解来配置。否则数据源配置一发生变化就得改代码。
下面是一种典型的混合配置示范:

在xml中配置数据源

<beans>
    <!-- 开启注解配置支持 -->
    <!-- <context:annotation-config/> -->
	  <!-- 扫描注解的包路径,配置了这个后无需再配置上面那个 -->
  	<context:component-scan base-package="com.lanou3g.spring"/>
    <!-- 读取properties配置文件,用于替换spring配置中的${}占位符 -->
  	<context:property-placeholder location="classpath:jdbc.properties"/>

    <bean class="com.acme.App"/>

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>

jdbc.url=jdbc:mysql://localhost:3306/XXXX(数据库名)?charsetEncoding=utf8
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root

通过java注解配置bean和依赖注入

@Configuration
public class App {

    @Autowired
    private DataSource dataSource;

    @Bean
    public Student student() {
        return new Student(dataSource);
    }

    @Bean
    public People people() {
        return new People(student());
    }
}

启动入口

public static void main(String[] args) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    People people = ctx.getBean(People.class);
    // ...
}

用注解的类导入xml配置

public interface Fruit {
    void eatFruit();
}

// 如果我们不写value属性,默认bean的名称就是类名首字母小写
// 这里就是banana
@Component
public class Banana implements Fruit {
    @Override
    public void eatFruit() {
        System.out.println("eating Banana");
    }
}

@Configuration // <beans>
public class MyConf {

    @Bean("sb") // <bean id="sb">
    public Fruit smallBanana() {
        return new Banana();
    }   
}

public class Student {
    private String sname;
    private String nickName;
    private Fruit fruit;

    public Student() {}

    public Student(String sname, String nickName, Fruit fruit) {
        this.sname = sname;
        this.nickName = nickName;
        this.fruit = fruit;
    }

    public String getSname() {
        return this.sname;
    }

    public String getNickName() {
        return this.nickName;
    }

    public Fruit getFruit() {return this.fruit;}

    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }
}

<!-- name属性也是用于给bean起名,getBean的时候使用,与id属性不同的是,name属性的值可以有多个 -->
    <bean id="student" name="stu,student1,sd1" class="com.lanou3g.spring.bean.Student">
        <constructor-arg name="nickName" value="三哥" />
        <constructor-arg name="sname" value="张三" />
        <constructor-arg name="fruit" ref="banana" />
    </bean>

public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher(). testAnnotationImportXml(ctx);
    } 

/**
     * 练习用@Configuration注解的类导入xml配置
     * @param ctx
     */
    public void testAnnotationImportXml(ApplicationContext ctx) {
        Fruit fruit = ctx.getBean("sb", Fruit.class);
        System.out.println(fruit);

        // 获取applicationContext.xml中配置的name属性为:stu,student1,sd1
        Student stu = ctx.getBean("sd1", Student.class);
        System.out.println(stu.getNickName());
    }

深入了解IOC

管理bean的作用域

Scope Description
singleton 单例。在整个ioc容器中只有一个此类型的示例。(默认值)
prototype 原型。每次使用都要创建一个新的对象。
request 对象的实例仅在一个request请求周期内有效,仅限在web环境中使用。
session 对象的实例仅在一个session会话周期内有效,仅限在web环境中使用。
application 对象的实例在整个application生命周期内有效,仅限在web环境中使用。
websocket 对象的实例仅在一个websocket生命周期内有效,仅限在web环境中使用。

常用的作用域只有两个:singleton,prototype。不写的话默认是singleton。

<bean id="md" class="com.lanou3g.spring.dao.MessageDaoImpl" scope="singleton"/>
public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testScope(ctx);
    }
public void testScope(ApplicationContext ctx){
        MessageDao messageDao1=ctx.getBean("md",MessageDao.class);
        System.out.println(messageDao1);

        MessageDao messageDao2=ctx.getBean("md",MessageDao.class);
        System.out.println(messageDao2);

        MessageDao messageDao3=ctx.getBean("md",MessageDao.class);
        System.out.println(messageDao3);

    }

管理bean的生命周期

 <bean id="md" class="com.lanou3g.spring.dao.MessageDaoImpl" scope="singleton"
          init-method="myInit" destroy-method="myDestroy"/>
    public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testLifeCycle(ctx);
    }

    /**
     * 练习IOC容器中bean的生命周期
     */
    public void testLifeCycle(ApplicationContext ctx) {
        MessageDao messageDao = ctx.getBean("md", MessageDao.class);
        System.out.println(messageDao);
    }

使用id属性和name属性命名bean

使用id属性命名bean

id属性的值只能指定一个,不建议含有特殊字符(虽然自spring3.1开始id属性的值可以包含任意字符)。

使用name属性命名bean

使用name属性可以给一个bean指定多个名称,多个值之间可以用","、";"或空格分开

注: 无论是id属性还是bean属性都需要保证整个IOC容器内唯一,并且id属性的值和name属性的值也不能重复

我们可以同时指定id和name属性。 也可以都不指定,如果都不指定,IOC容器会为该bean生成一个唯一的名称。

实例化bean的方式

通过构造方法实例化

这种方式是最常用的方式,适合绝大多数的javabean,因为我们的java类无需继承任何父类或实现任何接口。但是我们通常需要提供一个无参的构造方法。

通过静态工厂方法实例化

这种方式适合需要让Spring管理自己实现的单例类,用的很少。因为通过Spring IOC容器我们只需配置一下scope="singleton"就可以实现单例了。

通过非静态工厂方法实例化

这种方式用的也不多,只有特定场合才会用到。

三种实例化bean的方式代码如下:

 <!-- 通过构造方法创建bean -->
<!-- name属性也是用于给bean起名,getBean的时候使用,与id属性不同的是,name属性的值可以有多个 -->
    <bean id="student" name="stu,student1,sd1" class="com.lanou3g.spring.bean.Student">
        <constructor-arg name="nickName" value="三哥" />
        <constructor-arg name="sname" value="张三" />
        <constructor-arg name="fruit" ref="banana" />
    </bean>

 <!-- 通过静态工厂方法创建bean -->
    <bean id="big_apple" class="com.lanou3g.spring.bean.FruitFactory"  factory-method="produceFruit">
        <constructor-arg name="name" value="banana" />
    </bean>

 <!-- 通过非静态工厂方法创建bean -->
    <bean id="fruitFactory" class="com.lanou3g.spring.bean.FruitFactory" />
    <bean id="big_banana" factory-bean="fruitFactory" factory-method="produceFruitByInstrance">
        <constructor-arg name="name" value="banana" />
    </bean>

 public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testBeanInit(ctx);
    }

    /**
     * 练习bean的各种初始化配置
     */
public void testBeanInit(ApplicationContext ctx) {

        // 通过带参数构造方法初始化bean
        /*Student lazyStudent = ctx.getBean(Student.class);
        System.out.println("名称:" + lazyStudent.getSname());
        System.out.println("爱称:" + lazyStudent.getNickName());
        lazyStudent.getFruit().eatFruit();*/

        //通过静态工厂方法来初始化bean
        /*Object obj = ctx.getBean("big_apple");
        System.out.println(obj);*/

        // 通过非静态工厂方法来初始化bean
        Object obj = ctx.getBean("big_banana");
        System.out.println(obj);
        System.out.println(obj.getClass());
    }

优雅的关闭SpringIOC容器

我们可以通过registerShutdownHook()实现在JVM停止的同时优雅的关闭IOC容器

 public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
     // 给上面初始化的IOC容器添加一个基于JVM的关闭回调,  
     ctx.registerShutdownHook();
         // 其他业务代码...

   		// 在main方法运行结束后,IOC容器会在JVM的关闭回调中正常关闭
    }

懒加载

SpringIOC容器默认会在启动的时候初始化我们配置的所有bean,但有时我们想让一些bean延迟初始化的时机,在我们getBean的时候再初始化。

这时就需要使用懒加载,在bean上面添加lazy-init属性,属性值可以是true、false、default。 默认情况是false。

懒加载的优缺点:

对象使用的时候才去创建,节省资源,但是不利于提前发现错误。

<bean id="md" class="com.lanou3g.spring.dao.MessageDaoImpl" lazy-init="true"
      init-method="myInit" destroy-method="myDestroy"/>

Spring出现无法读取方案文档问题的解决办法

1.在pom.xml文件里添加如下配置

<plugins>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
  </plugin>
</plugins>

2.在标签下的中添加如下配置

  <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>2.4.3</version>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
          <configuration>
            <transformers>
              <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>com.lanou3g.spring.Launcher</mainClass>
              </transformer>
              <transformer
                      implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                <resource>META-INF/spring.schemas</resource>
              </transformer>
              <transformer
                      implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                <resource>META-INF/spring.handlers</resource>
              </transformer>
            </transformers>
          </configuration>
        </execution>
      </executions>
    </plugin>

3.把applicationContext.xml文件和message_beans.xml文件中的以xsd结尾的该行配置中的https改为http

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

DI

构造方法注入

package x.y;

public class ThingOne {
		private int age;
  	private String sname;
  	private int gender;
  	private ThingTwo thingTwo;
    public ThingOne(int age, ThingTwo thingTwo, String sname, int gender) {
        this.age = age;
				this.thingTwo = thingTwo;
      	this.sname = sname;
      	this.gender = gender;
  	    // ...
    }
}


public class ThingTwo {
  // ...
}

有参注入

无参注入

<beans>
	<!-- 有参注入 -->
    <bean id="beanOne" class="x.y.ThingOne">
        <!-- 通过此标签注入构造方法中的参数 -->
      	<constructor-arg  name="age" value="18" />
      	<constructor-arg  type="java.lang.String" value="张三" />	
      	<constructor-arg ref="beanTwo"/>
    </bean>
    
	<!-- 无参注入 -->
    <bean id="beanTwo" class="x.y.ThingTwo"/>
</beans>

通过c命名空间注入参数

先在beans中添加c的schema,再使用c代替标签

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 通过c命名空间来注入构造参数 -->
    <!--<bean id="yunjie2" class="com.lanou3g.spring.bean.YunJie">
        <constructor-arg name="sname" value="雲杰" />
    </bean>-->
    <!-- 等效于上面的配置 -->
    <bean id="yunjie2" class="com.lanou3g.spring.bean.YunJie" c:sname="雲杰" />
</beans>
	 public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testInjectC(ctx);
    }

/**
     * 测试通过c命名空间注入属性和构造参数
     */
    public void testInjectC(ApplicationContext ctx) {
        YunJie yunJie2 = ctx.getBean("yunjie2", YunJie.class);
        System.out.println("通过c注入构造参数, sname: " +yunJie2.getSname());
    }

setter注入

注入匿名内部bean

<!-- 给Student注入一个匿名内部bean -->
<bean id="stu1" class="com.lanou3g.spring.bean.Student">
    <property name="fruit">
        <bean class="com.lanou3g.spring.simple.Apple" />
    </property>
</bean>

	 public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testInjectInnerBean(ctx);
    }

/**
     * 通过<property>标签注入一个匿名内部类
     */
        public void testInjectInnerBean(ApplicationContext ctx){
            Student stu=ctx.getBean("stu1",Student.class);
            stu.getFruit().eatFruit();
        }

注入集合类属性

注入null,空字符串类型属性值

注入复合属性值

<bean id="saiSai" class="com.lanou3g.spring.bean.JinSaiSai">
    <property name="hobbies">
        <list>
            <value>游泳</value>
            <value type="java.lang.Integer">0034</value>
            <value>写代码</value>
            <value>玩游戏</value>
        </list>
    </property>
    
    <property name="gameTitles">
        <map>
            <entry key="LOL" value="嘴强王者"></entry>
            <entry key="王者农药" value="甩锅大神"></entry>
            <entry key="和平精英">
                <null />
            </entry>
        </map>
    </property>

    <property name="nickName">
        <null />
    </property>

    <property name="yinSaiSai">
        <bean class="com.lanou3g.spring.bean.YinSaiSai" />
    </property>
    <property name="yinSaiSai.age" value="28" />
</bean>

		 public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testInjectListMap(ctx);
    }


/**
     * 注入集合类属性
     *注入null,空字符串类型属性值
     *注入复合属性值
     */
        public void testInjectListMap(ApplicationContext ctx){
            JinSaiSai saisai=ctx.getBean(JinSaiSai.class);
            //获取注入的list属性
            List<Object> hobbies=saisai.getHobbies();
            for (Object hobby:hobbies) {
                System.out.println("类型:"+hobby.getClass()+",值:"+hobby);
            }

            //获取注入的map属性
            System.out.println(saisai.getGameTitles());

            //获取普通属性nickName
            System.out.println("nickName:"+saisai.getNickName());

            //获取关联对象中的属性值
            System.out.println("银赛赛中的age:"+saisai.getYinSaiSai().getAge());
        }

注入外部properties文件中的属性值

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

    <bean id="jdbcConf" class="com.lanou3g.spring.bean.JDBCConf">
        <property name="url" value="${jdbc.url}"/>
        <property name="driver" value="${jdbc.driver}"/>
        <property name="userName" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
			 public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testInjectProperties(ctx);
    }

    /**
     * 练习注入外部properties配置文件
     *
     */
      public void testInjectProperties(ApplicationContext ctx){
          JDBCConf jdbcConf=ctx.getBean(JDBCConf.class);
          System.out.println(jdbcConf.getUrl());
          System.out.println(jdbcConf.getDriver());
          System.out.println(jdbcConf.getUserName());
          System.out.println(jdbcConf.getPassword());
      }

通过p命名空间注入属性

先在beans中添加p的schema,再使用p代替标签

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 通过p命名空间来注入属性 -->
<!--<bean id="yunjie1" class="com.lanou3g.spring.bean.YunJie">
    <property name="sname" value="云姐" />
</bean>-->
<!-- 等效于上面的配置 -->
<bean id="yunjie1" class="com.lanou3g.spring.bean.YunJie" p:sname="云姐" />

</beans>
			 public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testInjectP(ctx);
    }

/**
     * 测试通过p命名空间注入属性和构造参数
     */
    public void testInjectP(ApplicationContext ctx) {
        YunJie yunJie1 = ctx.getBean("yunjie1", YunJie.class);
        System.out.println("yunjie1(通过p注入属性setter), sname: " + yunJie1.getSname());
    }

自动装配

byName

byType

byconstructor

/**
 * 演示lazy-init
 */
public class LazyHeJinJie {
    public void init() {
        System.out.println("LazyHeJinJie init");
    }

    public void destroy() {
        System.out.println("LazyHeJinJie over");
    }
}


/**
 * 自动装配属性byName
 */
@Getter
@Setter
public class AutoInjectByNameTeacher {
    private String tname;
    private Student student;
}

/**
 * 自动装配属性byType
 */
@Getter
@Setter
public class AutoInjectByTypeTeacher {

    public AutoInjectByTypeTeacher() {}

    public AutoInjectByTypeTeacher(LazyHeJinJie lazyHeJinJie) {
        System.out.println("构造参数传入: " + lazyHeJinJie);
        this.lazyStudent = lazyHeJinJie;
    }

    private String tname;
    private LazyHeJinJie lazyStudent;

    // 错误示范
    //    private Student student;
}

/**
 * 自动装配属性byconstructor
 */
@Getter
@Setter
public class AutoInjectByConstructorTeacher {

    public AutoInjectByConstructorTeacher() {}

    public AutoInjectByConstructorTeacher(LazyHeJinJie lazyHeJinJie) {
        System.out.println("构造参数传入: " + lazyHeJinJie);
        this.lazyStudent = lazyHeJinJie;
    }

    private String tname;
    private LazyHeJinJie lazyStudent;

    // 错误示范
    //    private Student student;
}

 <bean id="teacherByName" class="com.lanou3g.spring.bean.AutoInjectByNameTeacher"
        autowire="byName">
        <property name="tname" value="John" />
    </bean>

    <bean id="teacherByType" class="com.lanou3g.spring.bean.AutoInjectByTypeTeacher"
          autowire="byType">
        <property name="tname" value="John" />
    </bean>


    <bean id="teacherByConstructor" 				         class="com.lanou3g.spring.bean.AutoInjectByConstructorTeacher"
          autowire="constructor">
        <property name="tname" value="John" />
    </bean>
				 public static void main(String[] args) {
        // ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
       ClassPathXmlApplicationContext ctx = new          ClassPathXmlApplicationContext("applicationContext.xml");
         ctx.registerShutdownHook();
           new Launcher().testAutoInject(ctx);
    }

    /**
     *
     * 练习自动注入
     */
        public void testAutoInject(ApplicationContext ctx){
            //按照名称自动导入属性
            AutoInjectByNameTeacher teacher=ctx.getBean("teacherByName",AutoInjectByNameTeacher.class);
            System.out.println("教师名称:"+teacher.getTname());
            System.out.println("所教学生:"+teacher.getStudent().getSname());

            //按照类型自动注入属性(容器中符合此类型的bean只能有一个,否则报错)
            AutoInjectByTypeTeacher teacherByType=ctx.getBean("teacherByType",AutoInjectByTypeTeacher.class);
            System.out.println("教师名称(类型):"+teacherByType.getTname());
            teacherByType.getLazyStudent().destroy();

            // 构造器参数自动注入(按照类型)(容器中符合此类型的bean只能有一个,否则报错)
            AutoInjectByConstructorTeacher teacherByConstructor = ctx.getBean("teacherByConstructor" , AutoInjectByConstructorTeacher.class);
            System.out.println("教师名称(构造参数): " + teacherByConstructor.getTname());
            teacherByConstructor.getLazyStudent().destroy();

        }

猜你喜欢

转载自blog.csdn.net/zhanglu1995/article/details/93399048