Spring之依赖注入与 SPEL

  • 一、控制反转与依赖注入
  • 二、helloworld
  • 三、构造注入
  • 四、级联注入
  • 五、单例与多例
  • 六、工厂方法创建 Bean
  • 七、包扫描管理 bean
  • 八、SPEL与资源调用
  • 九、对象属性拷贝(自)
  • 十、单元测试
  • 十一、spring与 mybatis 整合

一、控制反转与依赖注入

IOC(Inversion of Control) 控制反转

  首先想说说 IOC(Inversion of Control)控制反转。这是 spring 的核心,贯穿始终。所谓 IOC,对于 spring 框架来说,就是由 spring 来负责控制对象的生命周期和对象间的关系。程序开发中,在一个对象中如果要使用另外的对象,就必须得到它常见的两种方式是自己 new 一个该对象,或者从 JNDI(Java 命名与目录接口(Java Naming and Directory Interface)中查询一个,使用完之后还要将对象销毁(比如 Connection 等),对象始终会和其他的接口或类藕合起来。

  Spring 所倡导的开发方式是这样,所有的类都会在 spring 容器中登记,告诉 spring 该类是做什么用,需要依赖其他什么类,然后 spring 会在系统运行到适当的时候,把需要的类对象主动注入到标记的位置,同时也把该类交给其他需要的地方。所有的类的创建、销毁都由 spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被 spring 控制,所以这叫控制反转。

DI(Dependency Injection) 依赖注入

  IOC 的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过 DI(Dependency Injection,依赖注入)来实现的。比如对象A 需要操作数据库,以前我们总是要在 A 中自己编写代码来获得一个 Connection 对象,有了 spring 我们就只需要告诉 spring,A 中需要一个 Connection,至于这个 Connection 怎么构造,何时构造,A 不需要知道。在系统运行时,spring 会在适当的时候制造一个 Connection,然后像打针一样,注射到 A 当中,这样就完成了对各个对象之间关系的控制。A 需要依赖 Connection 才能正常运行,而这个 Connection 是由 spring 注入到 A 中的,依赖注入的名字就这么来的。那么 DI 是如何实现的呢? Java 1.3 之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring 就是通过反射来实现注入的。

二、helloworld

  使用 maven 创建一个 web 项目,并添加 spring 上下文容器依赖。该依赖 spring 依赖其他几个 spring 常用依赖如:spring-aop、spring-beans、、spring-core、spring-expression 等。

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.12.RELEASE</version>
</dependency>

maven 会自动帮我们解决依赖之间的关联问题,如下为具体依赖关系图:

在项目中创建实体 User

public class User {private Integer id;private String name;
}

  配置 spring 容器的配置文件,在 resources 目录下点击 new -> XML Configuration File ->Spring Config 创建 spring-context.xml,并在其中配置一个 bean(被 spring 管理的对象)。

  其中 bean 的 id 表示该对象在容器中的唯一标识。class 表明该对象所属的类型。property 相当于对象的属性设置,spring 通过调研对象的 set 方法完成属性设置。

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="cn.hxzy.User"><property name="id" value="1"/><property name="name" value="张三"/></bean>
</beans>

  在主函数或测试类中获取 spring 的容器,并从容器中获取 bean 对象。

ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
// 从 IOC 容器中获取 bean 的实例
User bean = ctx.getBean(User.class);
System.out.println(bean);

  总结:如上操作即使用 spring 的语法在 spring 容器中创建一个被管理的对象。再通过 ApplicationContext(spring 上下文容器)获取该对象,ApplicationContext 是一个接口,常用的实现类有 ClassPathXmlApplicationContext:从类路径下加载 xml 配置文件获取 spring 上下文容器和 AnnotationConfigApplicationContext:从配置类中加载 spring 容器信息。通过容器获取 bean 常用三种方式如下:

Object getBean(String beanId) throws BeansException;
<T> T getBean(String beanId, Class<T> var2) throws BeansException;
<T> T getBean(Class<T> var1) throws BeansException;

  第一种是根据 bean 的 id 获取,由于容器无法确定返回类型,故返回结果为 Object 类型。第二种传入 bean 的类型故返回该类型的 bean。第三种根据类型获取 bean,当该类型的 bean 存在多个是 spring 启动会报错。

三、构造注入

  在实际开发中有时需要被管理的对象没有提供无参构造方法,因此我们需要在创建对象时直接传入对应的值。spring 使用 constructor-arg 设置对象的构造方法的参数,通常可以使用 name 指定构造方法的参数名或通过 index 指定构造方法参数的索引。比如: 与下面设置 id 的方式等效。

<bean id="user2" class="cn.hxzy.User"><constructor-arg name="name" value="李四"/><constructor-arg name="id" value="2"/>
</bean>

注意:在 xml 中包含特殊字符,必须使用<![CDATA[*****]]> 包裹,且不能在写在 constructor-arg 节点的属性上。

<constructor-arg name="name" ><value><![CDATA[<李四]]></value>
</constructor-arg>

练习:

1.创建项目 spring-fruit01,分别使用普通属性注入和构造注入的方式完成如下水果的创建。fruit(id,name,color)

fruit1(1,apple,red)属性注入

fruit2(2,banner,yellow)构造注入

fruit3(3,pear,white)构造加属性注入

fruit4(4,orange,)特殊字符注入

参考代码:

<bean id="fruit1" class="cn.hxzy.Fruit"><property name="id" value="1"/><property name="name" value="apple"/><property name="color" value="red"/>
</bean>
<bean id="fruit2" class="cn.hxzy.Fruit"><constructor-arg index="0" value="2"></constructor-arg><constructor-arg index="1" value="banner"></constructor-arg><constructor-arg index="2" value="yellow"></constructor-arg>
</bean>
<bean id="fruit3" class="cn.hxzy.Fruit"><constructor-arg name="id" value="3"></constructor-arg><constructor-arg name="name" value="pear"></constructor-arg><constructor-arg name="color" value="white"></constructor-arg>
</bean>
<bean id="fruit4" class="cn.hxzy.Fruit"><constructor-arg name="id" value="4"></constructor-arg><constructor-arg name="name" value="orange"></constructor-arg><constructor-arg name="color"><value><![CDATA[<orange>]]></value></constructor-arg>
</bean>

四、级联注入

  在 Spring 中可以通过一组内置的 xml 标签(例如:<list>,<set> 或 <map>)来配置集合属性。配置 java.util.List 类型的属性,需要指定 <list>标签,在标签里包含一些元素。这些标签可以通过 <value> 指定简单的常量值,通过<ref> 指定对其他 Bean 的引用。通过<bean> 指定内置 Bean 定义。通过 <null/> 指定空元素。甚至可以内嵌其他集合。数组的定义和 List 一样,都使用 <list> 配置 java.util.Set 需要使用 <set> 标签,定义元素的方法与 List 一样。

  在用户实体中加入 Car 集合

public class User {......private List<Car> cars;
}

汽车实体

public class Car {private String company;private Integer maxSpeed;private Float price;
}

  级联时使用 list 表明该处级联类型为 list 集合,里面使用 ref 应用其他 bean 对象,级联 set 与 map 也与此类似。

<bean id="user1" class="cn.hxzy.User"><property name="id" value="1"/><property name="name" value="张三"/><property name="cars"><list><ref bean="car1"/></list></property>
</bean>   <bean id="car1" class="cn.hxzy.Car"><property name="company" value="大众"/><property name="maxSpeed" value="280"/><property name="price" value="30"/>
</bean>

注意:设置为空使用下面的语法

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

练习:

1.创建项目 spring-fruit02,在基本属性设置的情况下增加特征(feature)和别名(otherName)两个级联属性。

Fruit{id=1, name=‘pear’, color=‘white’, feature={表皮=粗糙, 肉质=甜美}, otherName=[雪梨, 大鸭梨]}

public class Fruit {private Integer id;private String name;private String color;private Map<String, String> feature;private Set<String> otherName;
}

参考代码:

<bean id="fruit" class="cn.hxzy.Fruit"><property name="id" value="1"/><property name="name" value="pear"></property><property name="color" value="white"></property><property name="feature"><map><entry key="表皮" value="粗糙"/><entry key="肉质" value="甜美"/></map></property><property name="otherName"><set><value>雪梨</value><value>大鸭梨</value></set></property>
</bean>

五、单例与多例

  为了节省内存,spring 中的对象默认使用单例模式。即无论从容器中获取多少次对象,得到的都是同一个。但在实际开发中有时会用到多例,即希望每次从容器中获取对象都是新的对象。spring 提供 scop 属性来指定对象获取是单例还是多例。多例的 bean 又叫原型的。

  prototype:原型的。每次调用 getBean 方法都会返回一个新的 bean。且在第一次调用 getBean 方法时才创建实例。

  singleton:单例的。每次调用 getBean 方法都会返回同一个 bean。且在 IOC 容器初始化时即创建 bean 的实例。默认值

<bean id="user" class="cn.hxzy.User" scope="prototype"><property name="id" value="1"/><property name="name" value="张三"></property>
</bean>

应用场景:

  1.数据库连接 Connection 对象不能设计成单例,否则会出现多个线程使用同一个连接完成数据库的不同操作,也许上一个线程还没有查询完数据就会被下一个线程拿去修改数据库记录,非常容易出现错误。

  2.service 层的对象就不需要设计成原型的,因为 service 层没有过多的参数,不容易导致线程安全问题,创建过多的对象反而耗用大量内存意义不大。

六、工厂方法创建 Bean

  在项目开发中,有时需要使用工厂方法创建 bean,spring 支持常用的工厂方法如静态工厂方法创建和实例工厂方法创建 bean。

1.静态工厂方法创建 bean

public class CarFactory {static Map<String, Car> cars = new HashMap<>();static {cars.put("car1", new Car("宝马", 120, 122222.0));cars.put("car2", new Car("奥迪", 120, 122222.0));}public static Car getCar(String name) {return cars.get(name);}
}

获取 bean

<bean id="car1" class="cn.hxzy.CarFactory" factory-method="getCar"><constructor-arg value="car2"/>
</bean>

2.实例工厂方法获取 bean

public class CarFactory {Map<String, Car> cars = new HashMap<>();public CarFactory() {cars.put("car1", new Car("宝马", 120, 122222.0));cars.put("car2", new Car("奥迪", 120, 122222.0));}public Car getCar(String name) {return cars.get(name);}
}

获取bean

<bean id="carFactory" class="cn.hxzy.CarFactory"></bean>
<bean id="car1" factory-bean="carFactory" factory-method="getCar"><constructor-arg value="car1"></constructor-arg>
</bean>

七、包扫描管理 bean

  使用 xml 方式配置 bean 的依赖关系复杂且麻烦,为了解决对象在容器注入麻烦的问题,spring 推出了包扫描与声明类注解配合使用的方式,对于开发人员编写的类只需要在包扫描范围内,使用指定的声明类注解即可将对象加入 spring 容器中。

  sping 使用 context:component-scan 将指定包下面的带有声明 bean 的注解的类加入到 spring 容器管理。

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

  常用的声明类注解有如下几个,它们的功能和作用在 spring 中完全一模一样,都是将自己交给 spring 管理。唯一的区别就是它们所用的业务环节不同。

  • @Service 用于标注业务层组件
  • @Controller 用于标注控制层组件
  • @Repository 用于标注数据访问组件,即 DAO 组件
  • @Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

注入类注解:在 spring 容器管理的 bean 对象需要依赖其他 bean 对象时,就可以在对应对象属性或其 set 方法上使用注入类注解完成依赖注入。spring 容器中常用 @Autowired 和 @Resource 两个注解完成依赖注入。@Autowired 属于 Spring 的注解,@Resource 不属于 Spring 的注解,是 JDK1.6 支持的注解。它们的区别是:

@Autowired 默认按类型装配, 依赖对象必须存在,如果要允许 null 值,可以设置它的 required 属性为 false @Autowired(required = false) 也可以使用名称装配,配合 @Qualifier 注解

public class TestServiceImpl {@Autowired@Qualifier("userDao")private UserDao userDao;
}

@Resource 默认按名称进行装配,通过 name 属性进行指定,name 为属性的名字时可以省略。

案例:

dao 层模拟从数据库查出数据,首先需要使用声明类注解将自己注册到容器。

@Repository
public class PetDao {public List<Pet> getAll() {List<Pet> pets = new ArrayList<>();pets.add(new Pet("花花"));return pets;}
}

  service 层除了将自己注册到容器,还依赖 dao 层的对象,使用注入类注解将容器内的对象注入到对应位置。

@Service
public class PetService {@Autowiredprivate PetDao dao;public List<Pet> getAll() {return dao.getAll();}
}

view 层与服务层原理相同。

@Controller
public class PetView {@Resourceprivate PetService petService;public void getAll() {List<Pet> list = petService.getAll();System.out.println(list);}
}

main 从容器中获取 view 层对象即可调用它的方法,得到 dao 层返回的结果。

public class MainTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");PetView bean = context.getBean(PetView.class);bean.getAll();}
}

总结:将除了实体以外的其他对象加入 spring 容器管理,并通过彼此的依赖自动注入。使程序开发更加简便灵活,在内存耗用,对象管理方面更加优秀。

八、SPEL与资源调用


  内容如下:

<context:property-placeholder location="classpath:db.properties" file-encoding="utf-8"/>
<bean id="car1"><property name="company" value="${name}"/><property name="maxSpeed" value="280"/><property name="price" value="30"></property>
</bean>

  如果该属性需要的 spring 包扫描的类中使用可以使用 @Value("${name}") 获取配置文件内的属性。

@Service
public class PropertyTest {@Value("${name}")private String id;public String getId() {return id;}
}

  在 spring 中加载配置文件也可以使用注解的方式 @PropertySource(“classpath:db.properties”) 它与 context:property-placeholder 是等效的。

  spring 不仅仅可以获取配置文件里面的内容它还可以做一些简单的运算,如下案例:可以注入其他对象的属性、普通字符串、操作系统的信息、随机数、某个文件的内容等。如下代码在输出 Resource 时用到 commons-io 工具类。

  依赖如下:

<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.4</version>
</dependency>

  案例:

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;@Service
@PropertySource("classpath:db.properties")
public class PropertyTest {@Value("${id}")private int id;//注入配置文件的属性@Value("I love you")private String normal;//字符串原样注入@Value("#{systemProperties['os.name']}")private String osName;//注入操作系统信息@Value("#{pet.name}")private String otherName;//注入容器内其它 bean 的属性@Value("#{T (java.lang.Math).random()*100}")private Integer random;//注入 100 以下的随机数@Value("classpath:1.txt")private Resource resource;//注入classpath下文本文件里面内容@Value("http://58.42.239.163:8888/")private Resource resourceUrl;//注入网站地址的响应内容public String toString1() throws Exception {return "[normal=" + normal + ",id="+id+", osName=" + osName + ", otherName=" + otherName+ ", random=" + random + ", resource=" + IOUtils.toString(resource.getInputStream())+ ", resourceUrl=" + IOUtils.toString(resourceUrl.getInputStream(), "UTF-8") + "]";}
}

注意:

1.在 spring 通过注解 @Value 中获取 properties 文件里面的值使用 $ 前缀。

2.获取系统信息、容器类其他对象的信息、方法调用后的结果等使用 # 前缀。

3.获取文件或网页内容不使用前缀,且使用 Resource 接收。

九、对象属性拷贝(自)

  BeanUtils 在 spring 工具库中是比较常用的对象属性拷贝工具,BeanUtils.copyProperties(源头,目标);一般使用如下:

User user1 = .....;
User user2 = .....;
BeanUtils.copyProperties(user1,user2);

  当在完成两个对象拷贝是需要负略某些属性可以使用对应的重载方法 BeanUtils.copyProperties(源头,目标,“忽略的属性”); 但在实际开发中拷贝非空属性是比较常用的。创建方法将对象的非空属性列出后传入 BeanUtils 即可拷贝非空属性。

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import java.beans.PropertyDescriptor;
import java.util.HashSet;
import java.util.Set;public class BeanUtil {private static String[] getNullPropertyNames(Object source) {final BeanWrapper src = new BeanWrapperImpl(source);PropertyDescriptor[] pds = src.getPropertyDescriptors();Set<String> emptyNames = new HashSet<>();for (java.beans.PropertyDescriptor pd : pds) {Object srcValue = src.getPropertyValue(pd.getName());if (srcValue == null)emptyNames.add(pd.getName());}String[] result = new String[emptyNames.size()];return emptyNames.toArray(result);}public static void copyPropertiesIgnoreNull(Object source, Object target) {BeanUtils.copyProperties(source, target, getNullPropertyNames(source));}}

十、单元测试

  在实际开发中有时需要对 spring 容器中的大量的类和方法进行测试,使用 main 方法显然不能很好的满足需求,单元测试更好的解决测试方面的注入和运行问题。使用 spring 的单元测试需要导入相应的依赖:spring-test,同时要求 junit 不小于 4.12 版本。

<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.12.RELEASE</version><scope>test</scope>
</dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>

引入依赖后在测试源码目录下创建如下类并添加相应的注解

import cn.hxzy.spring.view.PetView;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:spring-context.xml")
public class AppTest {@Autowiredprivate PetView petView;@Testpublic void sendSimpleEmail() throws InterruptedException {petView.show();}
}

十一、spring与 mybatis 整合

  spring 能够与常见框架整合,如 mybatis,hibernate,redis 等。这使得大部分框架中的对象都可以从 spring 中获取到。而且对象被 spring 管理后可以很方便的使用 spring 的依赖注入和面向切面。

  使用 spring 与 mybatis 整合需要如下几步:

  1.添加依赖:由于数据库连接相关对象都交给 spring 管理,所以依赖中多出了 spring-jdbc 依赖。同时 mybatis 为了和 spring 整合开发了 mybatis-spring 整合包。

<!--spring -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.12.RELEASE</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.12.RELEASE</version>
</dependency><!--mybatis-->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.2</version>
</dependency>
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>

2.配置数据库连接信息,文件名通常为 db.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mydb
jdbc.username=root
jdbc.password=123456

3.spring 核心配置文件,由于数据库连接等对象都被 spring 管理,所以配置时不再需要 mybatis 的核心配置文件,如果在开发中确实需要用到 mybatis 的核心配置文件也可以配置 sqlsessionfactory 的 configlocation。

<?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" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><context:component-scan base-package="cn.hxzy"/><context:property-placeholder location="classpath:db.properties"/><!--    配置数据库数据源--><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><!--    创建 session 工厂--><bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="mapperLocations" value="classpath:mapper/*.xml"/></bean><!--告诉spring mybatis接口的位置--><bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="cn.hxzy.mapper"/></bean><!--    配置事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!--    使用注解的方式完成事务控制--><tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/></beans>

注意:

1.mapperScanner 配置主要配置 mybatis 的接口位置。

2.注解式事务是通过 @Transactional 注解即可完成该方法所有数据库操作要么一起成功,要么一起失败的业务逻辑。使用事务时数据库引擎必须使用 innoDB。

@Transactional
public  void update(){User user1 = new User();user1.setId(2);user1.setName("O");userMapper.update(user1);System.out.println(1 / 0);User user2 = new User();user2.setId(3);user2.setName("Y");userMapper.update(user2);
}

3.spring5 版本不再支持原来的 mybatis 章节的 log4j 版本,为了显示日志。通常我们使用 logback。导入如下依赖。

<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version>
</dependency>

配置文件 logback.xml 放在 classpath 下。

<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--控制台--><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p --- [%t] %-40.40logger{39} : %m%n</pattern></encoder></appender><!--根logger--><root level="DEBUG" additivity="false"><appender-ref ref="console"/></root>
</configuration>

章节练习:

1.IOC 综合练习:Boss,Car,Meeting 三个实体存在依赖关系如下:

Car:属性有 brand(品牌)、color(颜色)、parameter (参数 map)

Boss:属性有 name(名字)、company(公司全称)、car(拥有的车)

Meeting:属性 theme(主题)、bosses (会议主题在 meet.properties 文件中)

综合采用所学内容,设计并完成以上综合练习。一次会议包含 张三,李四和王二三个 Boss,他们每个人都有自己的爱车 car,使用 spring ioc 的 xml 方式配置这些对象。并在单元测试中输出结果如下:

Meeting{theme='全国程序员保护协会一次会议', bosses=[
Boss{name='张三', company='ABC', car=Car{brand='轩逸', color='红色', parameter={参考价=9.98-14.30万, 排量=1.6L}}},
Boss{name='李四', company='DEF', car=Car{brand='卡罗拉', color='白色', parameter={参考价=10.98-15.98万, 排量=1.2L,1.5L,1.8L}}},
Boss{name='王二', company='GHI', car=Car{brand='哈弗H6', color='白色', parameter={参考价=9.98-15.48万, 排量=1.5L,2.0L}}}]}

参考代码:

<context:property-placeholder location="classpath:meet.properties"/>
<bean id="car1" class="cn.hxzy.Car"><property name="color" value="红色"/><property name="brand" value="轩逸"/><property name="parameter"><map><entry key="参考价" value="9.98-14.30万"/><entry key="排量" value="1.6L"/></map></property>
</bean>
<bean id="car2" class="cn.hxzy.Car"><property name="color" value="白色"/><property name="brand" value="卡罗拉"/><property name="parameter"><map><entry key="参考价" value="10.98-15.98万"/><entry key="排量" value="1.2L,1.5L,1.8L"/></map></property>
</bean>
<bean id="car3" class="cn.hxzy.Car"><property name="color" value="白色"/><property name="brand" value="哈弗H6"/><property name="parameter"><map><entry key="参考价" value="9.98-15.48万"/><entry key="排量" value="1.5L,2.0L"/></map></property>
</bean>
<bean id="boss1" class="cn.hxzy.Boss"><property name="name" value="张三"/><property name="company" value="ABC"/><property name="car" ref="car1"/>
</bean>
<bean id="boss2" class="cn.hxzy.Boss"><property name="name" value="李四"/><property name="company" value="DEF"/><property name="car" ref="car2"/>
</bean>
<bean id="boss3" class="cn.hxzy.Boss"><property name="name" value="王二"/><property name="company" value="GHI"/><property name="car" ref="car3"/>
</bean>
<bean class="cn.hxzy.Meeting"><property name="bosses"><list><ref bean="boss1"></ref><ref bean="boss2"></ref><ref bean="boss3"></ref></list></property><property name="theme" value="${theme}"/>
</bean>

spring(一)依赖注入与 SPEL相关推荐

  1. factorybean 代理类不能按照类型注入_《Spring入门经典》:使用Spring进行依赖注入

    第二章:使用Spring进行依赖注入 重点:配置并使用Spring容器 使用不同类型的配置元数据来配置Spring容器 理解依赖解析 了解自动装配的优缺点 在容器中执行显式Bean查找 学习不同的Be ...

  2. 在ABAP里模拟实现Java Spring的依赖注入

    Dependency Injection- 依赖注入,在Java Spring框架中有着广泛地应用.通过依赖注入,我们不必在应用代码里繁琐地初始化依赖的资源,非常方便. 那么ABAP能否从语言层面上也 ...

  3. Spring Setter依赖注入示例

    学习如何编写Spring Setter依赖注入示例 . Setter注入是Spring依赖注入的一种 . Spring支持字段注入,Setter注入以及构造函数注入,以将依赖项注入Spring托管的b ...

  4. Spring字段依赖注入示例

    学习如何编写Spring Field Injection示例 . 字段注入是Spring框架 依赖注入的一种 . 在本教程中,我们将编写几个类,并看一看现场注入工程. 有关Spring依赖注入的更多信 ...

  5. 据说,80%的人没有真正理解了Spring的依赖注入

    前言 提起Spring,大家肯定不陌生,它是每一个Java开发者绕不过去的坎.Spring 框架为基于 java 的企业应用程序提供了一整套解决方案,方便开发人员在框架基础快速进行业务开发. 在官网中 ...

  6. Spring框架----Spring的依赖注入

    1.spring的依赖注入的概念 依赖注入:dependency Injection IOC的作用:降低程序之间的依赖关系,但不是消除. 依赖关系的管理:以后都交给了spring来维护 在当前类中需要 ...

  7. Spring和依赖注入的价值

    javaeye上看到有帖子,置疑spring和依赖注入的价值,回复内容整理如下: 依赖注入对设计有利,而spring则促进了依赖注入的使用. 如果业务处理类,它所使用的倚赖,都是依靠在这个类内部实现或 ...

  8. Spring实现依赖注入的几种方式

    Spring实现依赖注入的几种方式 1.基于有参构造实现 <bean id="user" class="com.ccu.twj"><const ...

  9. 【Spring】依赖注入的几种方式

    在上篇文章中我着重介绍了Spring的控制反转和依赖注入的概念,那么依赖注入有那几种方式呢?他们的优缺点分别是什么,我将在本章中详细讲解. Spring的依赖注入根据对象类型注入可以分为属性注入和对象 ...

最新文章

  1. python都学什么啊-Python到底有什么用?为什么那么多人都在学Python?
  2. Linux 常用命令二 pwd cd
  3. java:自定义数据库连接池
  4. mysql 触发器 运算符_mysql三元运算,上下连表,视图,触发器,存储过程,事务等不常用方法...
  5. SQL server常用查询
  6. 【图像处理】libtiff读写三维TIFF图像(附详细代码)
  7. 基于汇编的 C/C++ 协程 - 实现
  8. Gym 100796B Wet Boxes(思维)题解
  9. AD14简单使用教程
  10. 深度装机大师一键重装_电脑重装系统步骤
  11. texLive使用一条龙
  12. CBR,VBR,ABR,CQP四种编码方式。
  13. linux css压缩工具下载,推荐15个最好用的JavaScript代码压缩工具
  14. 统一通信系统解决方案
  15. 国外打工人分享如何如何通过销售excel电子表格赚到 28 万美元
  16. JavaScript中节点获取,节点的属性,如何操作节点
  17. Vue3 项目遇到的问题
  18. 最受DBA欢迎的数据库技术文档-巡检篇
  19. CE认证电气间隙和爬电距离要求
  20. 初步了解Panda3D场景管理

热门文章

  1. AR路由器通过web及代码实现公网用户使用公网地址访问内网服务器,同时内网用户实现通过公网地址访问内外那个服务器
  2. springcloud-alibaba-sentinel(1)sentinel流量卫兵介绍
  3. Web 开发中地图使用——高德地图定位功能
  4. 先选价、再叫车 高德打车首创上线“比价叫车”
  5. halcon印章文字提取
  6. 赵小楼:《天道》《遥远的救世主》深度解析(22)丁元英为什么不问肖亚文以后有什么打算?
  7. ChatGPT办公应用:制作PPT大纲
  8. seo和sem是什么意思
  9. unity3D埃及探险游戏源码,支持安卓+IOS双端 unity2019 C#语言开发
  10. HTML标签-排版标签、媒体标签、列表标签、表格标签、表单标签、语义化标签、字符实体