JavaWeb了解之Spring框架(Ioc容器篇)
2022-10-14 本文已影响0人
平安喜乐698
目录
前言
1. Spring框架结构
2. 第一个Spring项目(Hello World)
1. Spring IoC容器
2. 配置Bean (3种方式:XML、Java注解、Java代码)
3. 依赖注入
Spring是一款开源的Java框架(用于简化JavaEE开发)。
Spring框架的优点
1. 方便解耦,简化开发
将所有对象的创建和依赖关系的维护交给SpringIoC容器来管理。
2. 方便集成各种流行框架
Struts2、Hibernate、MyBatis等。
3. 降低JavaEE API的使用难度
对JavaEE开发中一些难用的API(如:JDBC、JavaMail、远程调用等)进行了封装。
4. 方便测试
支持JUnit4,可以通过注解 方便地测试Spring程序。
5. 支持AOP面向切面编程
降低通用功能和业务逻辑的耦合。
6. 支持声明式事务处理
只需通过配置就可完成对事务的管理。
前言
Spring框架
- Spring框架结构
Spring框架说明:
1. 核心容器(CoreContainer)
由以下4个模块组成 :
1. Beans模块
提供BeanFactory(一个工厂模式的复杂实现),包含访问配置文件、创建和管理Bean、进行IoC容器及DI依赖注入操作的所有类。
2. Core核心模块
提供了Spring框架基本的核心工具类(其他模块都会使用到)。
3. Context上下文模块
基于Core和Beans模块,可用于获取配置的任何对象(ApplicationContext接口),还提供了许多企业级功能支持。
4. SpEL表达式语言模块
访问和修改 属性值、数组、容器、索引器,方法调用,命名变量,算数和逻辑运算,从Spring容器获取Bean,列表投影、选择和一般的列表聚合等。
2. 数据访问/集成(DataAccess/Integration)
由以下5个模块组成 :
1. JDBC模块
提供了JDBC抽象层(对JDBC、事务等操作进行了封装)。
2. ORM模块
方便集成 对象/关系映射(JPA、JDO、Hibernate、iBatis)。
3. OXM模块
方便集成 Object/XML映射(JAXB、Castor、XMLBeans、JiBX、XStream) 。
4. JMS模块(Java消息服务)
提供了一套“消息生产者、消息消费者”模板来方便使用JMS。
JMS用于在两个应用之间或分布式系统中发送消息,进行异步通信。
5. Transactions模块
支持编程和声明式事务管理。
3. Web(MVC/Remoting)
由以下4个模块组成 :
1. Web模块
提供了基本的Web开发功能(如:多文件上传功能、使用Servlet监听器和Web应用上下文的IoC容器)。
2. Servlet模块
提供了Spring MVC Web框架实现(基于注解的请求资源注入、更简单的数据绑定、数据验证、JSP标签等)。
3. WebSocket模块
提供了快速搭建WebSocket Server实现双向通讯的接口。
4. Portlet模块
提供了在Portlet环境中使用MVC实现类似Web-Servlet模块的功能。
4.其他
1. AOP模块
提供了面向切面编程实现。提供 日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术(降低通用功能和业务逻辑的耦合)。
2. Aspects模块
提供与AspectJ(一个功能强大且成熟的面向切面编程AOP框架)的集成。
3. Instrumentation模块
提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。
4. Messaging模块
为STOMP提供了支持。
5. Test测试模块
支持JUnit、TestNG测试框架。
官网下载Spring框架、commons-logging-xxx.jar
Spring框架目录说明
1. docs
Spring的API文档、开发规范
2. libs
开发需要的jar
3. schema
开发所需要的schema文件(定义了Spring相关配置文件的约束)
libs目录下的jar说明
1. spring-core.jar(必须)
提供了基本的核心工具类(其它组件的核心)。
依赖第三方jar包:commons-logging-xxx.jar。
2. spring-beans.jar(必须)
提供了基础IoC功能(提供了进行IoC/DI操作相关的所有类:访问配置文件、创建和管理bean、其他相关的类)。
3. spring-context.jar(必须)
在基础IoC功能上进行了扩展(邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存、各种视图框架的封装)。提供了使用ApplicationContext时所需的全部类,JDNI所需的全部类,instrumentation组件以及校验Validation方面的相关类。
4. spring-expression.jar(必须)
提供了Spring表达式语言相关的所有类。
5. spring-aop.jar
提供了AOP特性相关的所有类。
6. spring-jdbc.jar
提供了SpringJDBC相关的所有类。
7. spring-tx.jar
提供了事务和异常处理相关的所有类(为JDBC、Hibernate、JDO、JPA等提供一致的声明式和编程式的事务管理)。
7. spring-web.jar
包含Web 应用开发时,用到Spring 框架时所需的核心类,包括自动载入Web Application Context 特性的类、Struts 与JSF 集成类、文件上传的支持类、Filter 类和大量工具辅助类。
外部依赖spring-context, Servlet API, (JSP API, JSTL, Commons FileUpload, COS)。
8. spring-webmvc.jar
包含Spring MVC 框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、Tiles、Velocity、XSLT相关类。包括框架的Servlets,Web MVC框架,控制器和视图支持。
如果应用使用了独立的MVC 框架,则无需这个JAR 文件里的任何类。
外部依赖spring-web, (spring-support,Tiles,iText,POI)。
9. spring-aspects.jar
提供对AspectJ的支持,以便可以方便的将面向方面的功能集成进IDE中,比如Eclipse AJDT。
10. spring-context-support.jar
Spring context的扩展支持,用于MVC方面。
11. spring-instrument.jar
Spring对服务器的代理接口
12. spring-instrument-tomcat.jar
Spring对tomcat连接池的集成
13. spring-jms.jar
为简化jms api的使用而做的简单封装。
外部依赖spring-beans,spring-dao,JMS API。
14. spring-orm.jar
整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现
15. spring-oxm.jar
Spring对于object/xml映射的支持,可以让JAVA与XML之间来回切换
16. spring-messaging.jar:
17. spring-test.jar
对JUNIT等测试框架的简单封装
19. spring-webmvc-portlet.jar
Spring MVC的增强
20. spring-websocket.jar:
- 第一个Spring项目(Hello World)
MyEclipse项目栏右击新建Java项目 | 点击项目右键 | Build Path | Config Build Path | Libraries | add External JARs | 1. 导入核心容器模块对应的4个jar(后期看需要再导入其他jar)或者 直接把spring的lib中所有的jar全部导入 ; 2. 导入commons-logging-xxx.jar
1. 新建HelloWorld.java文件(com.sst.cx包下)
package com.sst.cx;
public class HelloWorld {
private String message;
public void setMessage(String message){
this.message = message;
}
public void getMessage(){
System.out.println("Your Message : " + message);
}
public void init(){
System.out.println("Bean is going through init.");
}
public void destroy(){
System.out.println("Bean will destroy now.");
}
}
2. 新建HelloBeans.xml(src下)
定义各对象(分配唯一ID、属性赋值、依赖关系)。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.sst.cx.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
</beans>
3. 新建Main.java
获取配置文件中的HelloWorld类实例,并调用其getMessage方法
package com.sst.cx;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("HelloBeans.xml");
// HelloWorld obj = context.getBean("helloWorld", HelloWorld.class);
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
}
}
说明:
1. ClassPathXmlApplicationContext类用于加载Spring配置文件,创建并初始化所有Bean对象。
2. ApplicationContext.getBean()方法用于获取Bean,返回类型为Object。
4. 运行
Main.java文件 右键 | Run As Java Application运行程序,控制台会输出:
Your Message : Hello World!
添加Spring jar
运行
1. Spring IoC容器
Spring通过IoC容器来创建并管理所有Java对象(创建、初始化、依赖关系)。
1. IoC(Inversion of Control)控制反转
是一种设计思想(最大限度地降低耦合度)。
传统Java应用中,A类中想调用B类的属性或方法时,需要在代码中通过new创建B类的对象然后才能调用其属性或方法。A称为调用者,B称为被调用者,调用者掌握着被调用者的创建控制权。
在Spring应用中,所有Java对象的创建控制权都由Ioc容器掌握。首先在配置文件(3种方式:XML、Java注释、Java代码)中对各个对象及依赖关系进行配置;Spring启动时,IoC容器会加载并解析这些配置文件,根据对象定义及依赖关系利用Java的反射机制创建并管理对象(被IoC容器创建并管理的对象被称为SpringBean);当需要使用某个Bean时直接从IoC容器中获取,而不是通过new方式创建。Ioc容器实现解耦的原理:对象的信息及依赖关系都是在配置文件中定义的,而不是在代码中紧密耦合,当对象发生改变后只需修改配置文件,而无需对Java代码进行修改。
原本调用者为主动的一方,需要什么资源就自己去创建,在Spring中由IoC容器掌握主动权,原本的调用者需要被动的等待IoC容器创建自己所需的对象,即所谓的控制反转(控制权反转)。
2. DI(Denpendency Injection)依赖注入
A类中有一个类型为B类的属性(A的对象依赖于B的对象),Spring的IoC容器在创建对象时会自动根据依赖关系,将依赖对象注入到当前对象中,即所谓的依赖注入。
IoC容器的2种实现:
1. BeanFactory容器
提供了IoC容器的基本功能(功能最简单的容器)。
采用懒加载机制,Ioc容器在加载配置文件时并不会立即创建Java对象,只有在程序中使用到时才会创建。
移动设备或基于applet的应用的资源非常宝贵, 优先选择BeanFactory。
在org.springframework.beans.factory.BeanFactory接口中定义。BeanFactory相关的接口(BeanFactoryAware,InitializingBean,DisposableBean)向后兼容其他三方框架。
2. ApplicationContext容器
在org.springframework.context.ApplicationContext接口(BeanFactory接口的子接口)中定义。
对BeanFactory容器进行了扩展,增加了许多企业级功能(AOP、国际化、事务)。
常用的实现类:
1. FileSystemXmlApplicationContext
需提供XML文件的完整路径("/"代表项目根目录)。
2. ClassPathXmlApplicationContext
不需要提供XML文件的完整路径。
会在ClassPath下搜索XML文件(需正确配置ClassPath)。
3. WebXmlApplicationContext
在应用范围内搜索XML文件。
- BeanFactory容器
BeanFactory factory = new ClassPathXmlApplicationContext("HelloBeans.xml");
HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
obj.getMessage();
- ApplicationContext容器
// 创建和初始化所有对象(xml必须为完整路径, /代表项目根目录)
ApplicationContext context = new FileSystemXmlApplicationContext("/src/HelloBeans.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
// 容器销毁 context.registerShutdownHook();
2. 配置Bean (3种方式:XML、Java注解、Java代码)
由Spring IoC容器创建和管理的Java对象称为Bean(Bean根据Spring配置文件中的信息创建)。
1. 当无法在类中添加注解时(如:DataSource、JdbcTemplate等第三方库中的类),使用xml方式配置。
2. 当前项目中的类使用注解方式配置更好。
3. 可一起联合使用。
- XML方式配置
根元素为beans,可包含多个子元素bean(每一个bean元素对应一个Bean对象)。
<bean id="唯一标识" class="包路径.类名"></bean>
bean元素的常用属性
1. id
指定 Bean的唯一标识符(必须以字母开始,由字母、数字、下划线组成)
2. name
指定 Bean的名称(同一个Bean可指定多个名称,以,分隔)
3. class
指定 Bean对应的类(完整路径)。
4. scope
指定 【Bean的作用域】(5种)
1. singleton
单例(默认) ,(使用context.getBean方法)每次获取时都是同一个实例(仅对于该容器 即该容器共享同一个实例,一个Web应用会有多个容器)。
2. prototype
每次获取时都创建新的实例。
// ---------以下只在web的ApplicationContext的上下文中有效(XmlWebApplicationContext) ---------
3. request
每次HTTP请求都会创建一个实例。
4. session
同一个HTTP会话共享同一个实例。
5. application
同一个Web应用共享同一个实例。
6. websocket
在整个WebSocket中有效
5. lazy-init
延迟加载。设为true则使用时才会创建Bean实例;设为false则容器启动时就创建Bean实例。
该方法只在scope=singleton时有效。
6. init-method
容器加载Bean时(所有必需的属性被容器设置之后)会调用该方法。
7. destroy-method
容器删除Bean时(容器被销毁时会删除容器中的Bean)会调用该方法。
该方法只在scope=singleton时有效。
对于初始化方法和销毁非法,分为全局指定和单个类指定:
1. 全局指定:在beans元素中加 default-init-method="init" default-destroy-method="destroy"。
2. 单个类指定:在bean元素中加 init-method="init" destroy-method="destroy"。
8. parent
指定父Bean,与Java类的继承无关(子Bean和父Bean对应的实例不需要有继承关系)。子Bean可以继承父Bean的配置数据,也可以根据需要重写或添加属于自己的配置信息。
例:
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message1" value="Hello"/>
<property name="message2" value="World"/>
</bean>
<bean id="helloIndia" class="com.sst.cx.HelloIndia" parent="helloWorld">
<property name="message1" value="Hi"/>
<property name="message3" value="Hello World"/>
</bean>
9. abstract
设置为true,可将父Bean定义为抽象模版(表明这个Bean是抽象的,不能被实例化,也不能被其他Bean引用,只能在子Bean的parent中引用)。
例:
<bean id="beanTeamplate" abstract="true">
<property name="message1" value="Hello World!"/>
<property name="message2" value="Hello Second World!"/>
<property name="message3" value="Namaste India!"/>
</bean>
10. autowire(自动装配)
把Bean与Bean之间建立依赖关系的行为称为装配。
Spring容器可以在不使用<constructor-arg>和<property>的ref属性情况下,通过bean元素的autowire自动装配属性(根据装配规则为Bean从应用上下文中查找它所依赖的Bean并建立依赖关系)来简化XML内容。仍然可以使用ref属性进行“重写”。
装配规则(5种)
1. no
不使用自动装配(默认)。
2. byName
按属性名自动装配。
从所有IoC容器中寻找id/name和(使用自动装配bean对应实例的)属性名相同的bean,并建立依赖关系。
3. byType
按属性数据类型自动装配。
从所有IoC容器中寻找class和(使用自动装配bean对应实例的)属性类型相同的bean,并建立依赖关系(如果存在多个对应的bean则异常)。
4. constructor
类似于byType,按构造函数的参数类型自动装配。
从所有IoC容器中寻找class和(使用自动装配bean对应实例的)构造参数类型相同的bean,并建立依赖关系(如果不存在对应的构造函数参数类型的bean则异常)。
5. default
使用beans元素中的自动装配规则(beans元素的default-autowire属性)。
自动装配的局限性:不能自动装配基础数据类型;没有显式装配精确。
bean元素的子元素(分别对应属性注入的2种方式)
1. constructor-arg
通过Bean实例的带参构造函数实现Bean的属性注入(一个constructor-arg元素对应一个需要注入的属性)。
name属性指定对应的构造参数名,value属性指定参数值。
index属性指定构造参数的序号(从0开始)。type属性指定构造参数的类型。
2. property
通过Bean实例的setter方法实现Bean的属性注入(一个property元素对应一个需要注入的属性)。
name属性指定Bean实例相应的属性名,value属性指定属性值。
constructor-arg元素、property元素、其他元素的子元素
1. ref
用于引用某个Bean实例(Bean元素的id/name)
2. value
用于指定一个常量值
3. list
注入 List或数组类型的属性
4. set
注入 Set类型的属性
5. map
注入 Map类型的属性
6. entry(map元素的子元素)
用于设置一个键值对
key属性指定字符串类型的键,ref或value子元素指定其值。
示例
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--
懒加载:lazy-init="true"
初始化方法:init-method
销毁方法:destroy-method
-->
<bean id="..." class="..." lazy-init="true" init-method="..." destroy-method="...">
</bean>
</beans>
- 注解方式配置(简化xml文件内容)
通过注解可以在不改变原有代码逻辑的情况下,在源代码中嵌入补充信息。
从Spring2.5开始,可以对类、方法、属性添加注解来实现:配置Bean,实现依赖注入(会在xml配置的注入之前执行,所以会被覆盖)、自动装配。
1. 需要在xml配置文件中,开启注解功能。
<!-- 会扫描包下的类,从类的注解中获取Bean的定义信息。例如:开启后如果类使用了@Component注解,则将该类配置到容器中。 -->
<context:component-scan base-package="net.biancheng.c"></context:component-scan>
<!-- 开启注解功能 -->
<context:annotation-config/>
2. 配置Bean的注解(会被添加到IoC容器中)
1. @Component注解
将类标识为Bean。
2. @Repository注解
将Dao层(数据访问层)的类标识为Bean。
3. @Service注解
将Service层(业务层)的类标识为Bean。
4. @Controller注解
将Controller层(控制层)的类标识为Bean(如:Struts2的Action、SpringMVC的Controller)。
例:@Component("helloBean")、@Repository("userDaoImpl")
5. @Scope注解
指定Bean的作用域
3. 实现依赖注入的注解
1. @Autowired注解(自动装配,默认使用byType自动装配规则)
可用在setter方法、非setter方法、构造函数、属性。
1. 用在setter方法上(会自动使用byType,不用设置property)
@Autowired
public void setHelloB(HelloB helloB) {
this.helloB = helloB;
}
2. 用在属性上(会自动使用byType,不用设置set方法)
@Autowired
HelloB helloB;
3. 用在构造函数上(会自动使用byType,不用设置property)
@Autowired
public HelloWorld(HelloB helloB) {
this.helloB = helloB;
}
4. 当没有匹配到时会报NoSuchBeanDefinitionException异常,可设置required属性为false来避免。
@Autowired(required=false) 设为非必须(默认是必须的)
2. @Qualifier注解(与@Autowired注解配合使用:@Autowired + @Qualifier)
当匹配到多个相同类型的bean时使用,将自动装配规则由默认的byType修改为byName。
例:
@Autowired
@Qualifier("helloB1")
private HelloB helloB;
3. @Resource注解(自动装配,默认使用byName自动装配规则)
如果指定name属性,则按byName进行装配;
如果指定type属性,则按byType进行装配;
如果都不指定,则先按byName进行装配,如果没有找到则再按byType进行装配;如果都无法匹配,则抛出NoSuchBeanDefinitionException异常。
4. @Value注解(注入普通属性值)
@Value("张三")
5. @Nullable注解(注入null)
4. 生命周期相关的注解
1. @PostConstruct注解
标识为初始化方法(指定为init-method)
2. @PreDestroy注解
标识为销毁方法(指定为destroy-method)
5. 其他
1. @Required注解
用于setter方法上。表示相应的bean属性必须进行注入,否则BeanInitializationException异常。
例:
@Required
public void setName(String name) {
this.name = name;
}
<bean id="helloWorld" class="com.sst.cx.HelloWorld">
<property name="name" value="cx"/>
</bean>
2. @Test注解
- Java代码方式配置
可以完全摆脱xml配置文件。
配置类相关的注解
1. @Configuration注解
标识该类为配置类(一个配置类等价于一个xml配置文件)。
获取容器:ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
当有多个配置类时:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
2. @Bean注解
将该类注册到IoC容器中(所修饰的方法相当于Bean的id属性,方法返回类型相当于Bean的class属性)。
获取容器中的对象:Foo foo = ctx.getBean(Foo.class);
3. @Import注解
导入其他配置类(从其他配置类中加载@Bean定义)。
例:
@Import(ConfigA.class)
@Configuration
public class AppConfig {
@Bean
public Foo foo() {
return new Foo(bar()); // 依赖注入
}
@Bean
public Bar bar() {
return new Bar();
}
@Bean(initMethod = "init", destroyMethod = "cleanup" )
public HelloB helloB(){ // HelloB类中有init、cleanup方法
return new HelloB();
}
@Bean
@Scope("prototype")
public HelloB helloB(){
return new HelloB();
}
}
Bean生命周期
主要分为
1. 实例化阶段
向容器请求一个尚未初始化的bean时 或 初始化bean时需要注入另一个尚末初始化的依赖时,容器就会调用doCreateBean()方法创建Bean并进行实例化(给属性赋值属性)。
2. 初始化阶段
1. 执行Aware接口的方法(如果Bean实现了xxxAware接口)。通过Aware类型的接口可以获取到Spring容器的一些资源。如:实现BeanNameAware接口可以获取到BeanName,实现BeanFactoryAware接口可以获取到工厂对象BeanFactory等。
2. 执行BeanPostProcessor的前置处理方法postProcessBeforelnitialization()方法(如果Bean实现了BeanPostProcessor接口),此时Bean已经创建但未初始化。
3. 执行afeterPropertiesSet()初始化方法(如果Bean实现了InitializingBean接口)
4. 执行自定义的初始化方法(如果在bean元素的init-method属性中进行了配置)。
5. 执行BeanPostProcessor的后置处理方法postProcessAfterinitialization()方法(如果Bean实现了BeanPostProcessor接口)此时Bean已经初始化。
3. 销毁阶段
1. 执行DestructionAwareBeanPostProcessor后置处理方法postProcessBeforeDestruction()方法(如果Bean实现了DestructionAwareBeanPostProcessor接口)。
2. 执行DisposableBean的destroy()方法(如果Bean实现了DisposableBean接口)。
3. 执行自定义的销毁方法(如果在bean元素的destroy-method属性中进行了配置)。
Bean的生命周期
后置处理器
Spring提供了如下后置处理器
1. BeanFactoryPostProcessor
2. BeanPostProcessor
3. InitializingBean
如果bean实现了以上接口中的方法,这些方法会在bean初始化时调用,可以做一些前置、后置处理。
例(BeanPostProcessor)
===》InitHelloWorld.java
package com.sst.cx;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class InitHelloWorld implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeforeInitialization : " + beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("AfterInitialization : " + beanName);
return bean;
}
}
3. 依赖注入(即给属性赋值)
2种:
1. 基于构造函数的属性注入
2. 基于setter的属性注入
- 基于构造函数的属性注入
通过Bean实例的带参构造函数实现Bean的属性注入。
1. 根据构造函数的参数名
<bean id="student" class="net.biancheng.c.Student">
<constructor-arg name="id" value="2"></constructor-arg>
</bean>
2. 根据构造函数的参数顺序
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="2001"/>
<constructor-arg type="java.lang.String" value="Zara"/>
</bean>
或
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="2001"/>
<constructor-arg index="1" value="Zara"/>
</bean>
示例
1. Grade年级类
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Grade {
private static final Log LOGGER = LogFactory.getLog(Grade.class);
private Integer gradeId;
private String gradeName;
public Grade(Integer gradeId, String gradeName) {
LOGGER.info("正在执行 Course 的有参构造方法,参数分别为:gradeId=" + gradeId + ",gradeName=" + gradeName);
this.gradeId = gradeId;
this.gradeName = gradeName;
}
@Override
public String toString() {
return "Grade{" +
"gradeId=" + gradeId +
", gradeName='" + gradeName + '\'' +
'}';
}
}
2. Student学生类
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Student {
private static final Log LOGGER = LogFactory.getLog(Student.class);
private int id;
private String name;
private Grade grade;
public Student(int id, String name, Grade grade) {
LOGGER.info("正在执行 Course 的有参构造方法,参数分别为:id=" + id + ",name=" + name + ",grade=" + grade);
this.id = id;
this.name = name;
this.grade = grade;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", grade=" + grade +
'}';
}
}
3. xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="student" class="net.biancheng.c.Student">
<constructor-arg name="id" value="2"></constructor-arg>
<constructor-arg name="name" value="李四"></constructor-arg>
<constructor-arg name="grade" ref="grade"></constructor-arg>
</bean>
<bean id="grade" class="net.biancheng.c.Grade">
<constructor-arg name="gradeId" value="4"></constructor-arg>
<constructor-arg name="gradeName" value="四年级"></constructor-arg>
</bean>
</beans>
4. 测试
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
private static final Log LOGGER = LogFactory.getLog(MainApp.class);
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Student student = context.getBean("student");
LOGGER.info(student.toString());
}
}
- 基于setter的属性注入
通过Bean实例的setter方法实现Bean的属性注入。
根据属性名
<bean id="student" class="net.biancheng.c.Student">
<property name="id" value="1"></property>
<property name="grade" ref="grade"></property>
</bean>
在Spring实例化Bean的过程中,IoC容器首先会调用默认的构造方法(无参构造方法)实例化Bean(Java对象),然后通过Java的反射机制根据属性名调用Bean的setter方法 将属性值注入到Bean中。
有其他带参构造函数时需创建一个无参构造函数(没有其他带参构造函数时无需创建)。
示例
1. Grade年级类
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Grade {
private static final Log LOGGER = LogFactory.getLog(Grade.class);
private Integer gradeId;
private String gradeName;
// 无参构造方法。在没有其他带参构造方法时可以省略。
public Grade() {
}
public void setGradeId(Integer gradeId) {
LOGGER.info("正在执行 Grade 类的 setGradeId() 方法…… ");
this.gradeId = gradeId;
}
public void setGradeName(String gradeName) {
LOGGER.info("正在执行 Grade 类的 setGradeName() 方法…… ");
this.gradeName = gradeName;
}
@Override
public String toString() {
return "Grade{" +
"gradeId=" + gradeId +
", gradeName='" + gradeName + '\'' +
'}';
}
}
2. Student学生类
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Student {
private static final Log LOGGER = LogFactory.getLog(Student.class);
private int id;
private String name;
private Grade grade;
// 无参构造方法。在没有其他带参构造方法时可以省略。
public Student() {
}
public void setId(int id) {
LOGGER.info("正在执行 Student 类的 setId() 方法…… ");
this.id = id;
}
public void setName(String name) {
LOGGER.info("正在执行 Student 类的 setName() 方法…… ");
this.name = name;
}
public void setGrade(Grade grade) {
LOGGER.info("正在执行 Student 类的 setGrade() 方法…… ");
this.grade = grade;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", grade=" + grade +
'}';
}
}
3. xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="student" class="net.biancheng.c.Student">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="grade" ref="grade"></property>
</bean>
<bean id="grade" class="net.biancheng.c.Grade">
<property name="gradeId" value="3"></property>
<property name="gradeName" value="三年级"></property>
</bean>
</beans>
- 短命名空间注入(对上述2种方式进行简化)
1. c命名空间(构造函数方式注入的快捷实现)
需要在beans元素中引入XML约束xmlns:c="http://www.springframework.org/schema/c"
以bean属性的形式(c:普通属性="属性值" c:对象属性="对象的引用")代替<constructor-arg> 元素。
2. p命名空间(setter方式注入的快捷实现)
需要在beans元素中引入XML约束xmlns:p="http://www.springframework.org/schema/p"
以bean属性的形式(p:普通属性="属性值" p:对象属性="对象的引用")代替<property> 元素。
- 注入内部Bean(属性类型为类类型)
将定义在property元素、constructor-args元素内部的bean称为内部bean。
例(HelloWorld类有一个HelloB类型属性helloB,HelloB类有个name属性)
方式1. setter方式注入(需要一个无参构造函数、一个set方法)
<bean id="helloWorld" class="com.sst.cx.HelloWorld">
<property name="helloB">
<bean class="com.sst.cx.HelloB">
<property name="name" value="张三"/>
</bean>
</property>
</bean>
方式2. 构造函数方式注入(构造函数需要一个HelloB类型的参数helloB)
<bean id="helloWorld" class="com.sst.cx.HelloWorld">
<constructor-args name="helloB">
<bean class="com.sst.cx.HelloB">
<constructor-args name="name" value="张三"/>
</bean>
</constructor-args>
</bean>
- 注入集合(属性类型为集合)
在property元素中添加如下子元素来配置集合值:
1. list元素
注入一列值(允许重复)
2. set元素
注入一列值(不能重复)
3. map元素
注入键值对(键值可以是任何类型)
4. props元素
注入键值对(键值都为字符串类型)
5. array元素
注入
注入引用(集合中的元素为类类型时)
<property name="addressSet或addressList">
<list>
<value>A</value>
<ref bean="helloBean"/>
</list>
</property>
<property name="addressMap">
<map>
<entry key="one" value="A"/>
<entry key ="two" value-ref="helloBean"/>
</map>
</property>
<property name="addressArray">
<array>
<ref bean="helloBean"/>
</array>
</property>
示例
1. HelloWorld.java
package com.sst.cx;
import java.util.*;
public class HelloWorld {
private List<String> addressList;
private Set<String> addressSet;
private Map<String,String> addressMap;
private Properties addressProp;
private String[] addressArray;
//
public List getAddressList() {
System.out.println("List Elements :" + addressList);
return addressList;
}
public void setAddressList(List<String> addressList) {
this.addressList = addressList;
}
public Set getAddressSet() {
System.out.println("Set Elements :" + addressSet);
return addressSet;
}
public void setAddressSet(Set<String> addressSet) {
this.addressSet = addressSet;
}
public Map getAddressMap() {
System.out.println("Map Elements :" + addressMap);
return addressMap;
}
public void setAddressMap(Map<String,String> addressMap) {
this.addressMap = addressMap;
}
public Properties getAddressProp() {
System.out.println("Property Elements :" + addressProp);
return addressProp;
}
public void setAddressProp(Properties addressProp) {
this.addressProp = addressProp;
}
public String[] getAddressArray() {
System.out.println("Array Elements :" + addressArray);
return addressArray;
}
public void setAddressArray(String[] addressArray) {
this.addressArray = addressArray;
}
}
2. Beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.sst.cx.HelloWorld">
<property name="addressList">
<list>
<value>A</value>
<value>B</value>
<value>C</value>
<value>C</value>
</list>
</property>
<property name="addressSet">
<set>
<value>A</value>
<value>B</value>
<value>C</value>
<value>C</value>
</set>
</property>
<property name="addressMap">
<map>
<entry key="1" value="A"/>
<entry key="2" value="B"/>
<entry key="3" value="C"/>
<entry key="4" value="C"/>
</map>
</property>
<property name="addressProp">
<props>
<prop key="one">A</prop>
<prop key="two">B</prop>
<prop key="three">C</prop>
<prop key="four">C</prop>
</props>
</property>
<property name="addressArray">
<array>
<value>A</value>
<value>B</value>
<value>C</value>
<value>C</value>
</array>
</property>
</bean>
</beans>
3. Main.java
package com.sst.cx;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
HelloWorld helloW = (HelloWorld)context.getBean("helloWorld");
helloW.getAddressList();
helloW.getAddressSet();
helloW.getAddressMap();
helloW.getAddressProp();
}
}
- 注入其他类型
除了基础数据类型属性、类类型属性、集合外,也支持注入其他类型:Null值、特殊符号。
null值
<property name="nullValue">
<null/>
</property>
特殊符号
在XML配置文件中"<、>、"、'、&"等特殊字符是不能直接保存的,否则XML语法检查时就会报错。
解决:
方式1. 转义后保存。
转义序列字符之间不能有空格;
转义序列必须以“;”结束;
单独出现的“&”不会被认为是转义的开始;
区分大小写
方式2. 将特殊符号包含在<![CDATA[特殊符号写在这里]]>中。
不允许嵌套;]]>不能有空格或换行;
<property name="num">
<![CDATA[<<12345678>>]]>
</property>