文章目录
一.Ioc和DI
-
IoC:Inverse of Control(控制反转):
指将对象的创建权,反转给了Spring容器; -
DI:Dependency Injection(依赖注入):
指Spring创建对象的过程中,将对象依赖属性(简单值,集合,对象)通过配置设值给该对象。
二.Hello World
步骤:
- 准备jar包
- spring-beans-4.2.4.RELEASE.jar
- spring-core-4.2.4.RELEASE.jar
- 报错再添加:
- commons.logging-1.2.jar
- 开发HelloWorld程序
- 在applicationContext.xml中完成配置(docs\spring-framework-reference\html\xsd-config.html)
- 启动容器
- 从容器中得到bean
- 调用bean响应的方法
HelloWorld类
@Setter@Getter@ToString
public class HelloWorld {
private String name;
}
测试类App
public class App {
//使用Spring的方式来创建对象和给对象属性赋值
@Test
public void Ioc() {
//1:在classpath路径中找到applicationContext.xml配置文件
Resource resource = new ClassPathResource("applicationContext.xml");
//2:根据配置文件创建BeanFactory
XmlBeanFactory factory = new XmlBeanFactory(resource);
//3:从工厂中获取id为helloWorld的bean对象
//方式1:getBean(String beanName)根据bean的id/name属性的值获取bean对象
//HelloWorld world = (HelloWorld) factory.getBean("helloWorld");
//方式2:getBean(Class<?> type)根据bean的类型来获取bean对象
//HelloWorld world = factory.getBean(HelloWorld.class);
//方式3:getBean("",HelloWorld.class)
HelloWorld world = factory.getBean("helloWorld", HelloWorld.class);
System.out.println(world);
}
//模拟Spring管理bean的原理
@Test
public void testMock() throws Exception {
String className = "com.dusk._1_hello.HelloWorld";
//反射
Class<?> clz = Class.forName(className);
//获取无参构造器
Constructor<?> con = clz.getDeclaredConstructor();
//可以访问私有变量
con.setAccessible(true);
Object obj = con.newInstance();
//内省的方式个对象属性赋值
PropertyDescriptor[] pds = Introspector.getBeanInfo(clz, Object.class).getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
if(pd.getName().equals("name")){
pd.getWriteMethod().invoke(obj,"真.西门吹.牛");
}
}
HelloWorld world = (HelloWorld) obj;
System.out.println(world);
}
}
放在和类同一级目录文件下
HelloWorld.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.xsd">
<!--IoC:把bean交给Spring管理-->
<bean id="helloWorld" class="com.dusk._1_hello.HelloWorld">
<!--DI:给对象的属性赋值-->
<property name="name" value="真.红眼黑龙"/>
</bean>
</beans>
放在资源文件Resource下
applicationContext.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.xsd">
<import resource="classpath:com/dusk/_1_hello/helloworld.xml"/>
</beans>
三.Spring基本配置
-
在Spring配置中,id和name属性都可以定义bean元素的名称,不同的是:
id属性,遵守XML语法的ID约束(唯一)。必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号,不能以“/”开头。- name属性,就可以使用很多特殊字符,比如在Spring和Struts1或Spring
- MVC的整合中,就得使用name属性来的定义bean的名称。
<bean name="/login" class="cn.wolfcode.pss.web.action.LoginAction" />
== 注意:从Spring3.1开始,id属性不再是ID类型了,而是String类型,也就是说id属性也可以使用“/”开头了,而bean元素的id的唯一性由容器负责检查。==
- 引入其他配置文件
可以将一个applicationContext.xml文件分解成多个配置文件,然后在applicationContext.xml文件中包含其他配置文件即可。
使用import元素引入其他的配置文件:
<import resource="classpath:cn/wolfcode/hello/hello.xml"/>
使用import元素注意:
- 默认情况下,从classpath的根路径寻找。
- 可以使用前缀来定位文件的基础位置:
- [classpath:]:后面的文件从classpath路径开始找(推荐);[注意classloader的问题。]
- [file:]:后面的文件使用文件系统的路径开始找;
注意:只有当框架中实现了Resource接口才能够识别上述的前缀标识符。
四.Spring整合JUnit测试
Spring整合JUnit依赖jar:
Spring4.x需要依赖的单元测试得是最新的junit4.12,Eclipse3.7自带的junit4.8不支持,同时从Spring4.x开始,还得依赖AOP包的支持。
junit-4.12.jar
hamcrest-core-1.3.jar
spring-test-4.2.4.RELEASE.jar
spring-context-4.2.4.RELEASE.jar
spring-aop-4.2.4.RELEASE.jar
spring-expression-4.2.4.RELEASE.jar
若:
把@ContextConfiguration(“classpath:applicationContext.xml”) 写成@ContextConfiguration
默认去找的当前测试类名-context.xml配置文件,如:HelloWorldTest-context.xml
SpringTest类
//Spring整合JUnit测试框架
//RunWith表示容器直接运行在JUnti上,测试类运行在Spring容器中
@RunWith(SpringJUnit4ClassRunner.class)
//ContextConfiguration:告诉测试框架Spring配置文件的位置
@ContextConfiguration
public class SpringTest {
//自动装配
//表示在容器中找到对应的对象,自动注入过来
@Autowired
private HelloWorld world;
@Test
public void testOld(){
//自己创建容器
Resource resource = new ClassPathResource("applicationContext.xml");
XmlBeanFactory factory = new XmlBeanFactory(resource);
//从容器中取出对象
HelloWorld world = factory.getBean("helloWorld", HelloWorld.class);
System.out.println(world);
}
@Test
public void testSpringTest(){
//自己创建容器
System.out.println(world);
}
}
SpringTest-context.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.xsd">
<!--IoC:把bean交给Spring管理-->
<bean id="helloWorld" class="com.dusk._2_test.HelloWorld">
<!--DI:给对象的属性赋值-->
<property name="name" value="真.红眼黑龙"/>
</bean>
</beans>
HelloWorld类
@Setter@Getter@ToString
public class HelloWorld {
private String name;
}
五.IoC容器
IoC容器:BeanFactory和ApplicationContext对象
BeanFactory:是Spring中最底层的接口,只提供了最简单的IoC功能,负责配置,创建和管理bean。
在应用中,一般不使用BeanFactory,而推荐使用ApplicationContext(应用上下文),原因如下。
BeanFactory和ApplicationContext的区别:
- ApplicationContext继承了BeanFactory,拥有了基本的IoC功能;
- 除此之外,ApplicationContext还提供了以下的功能:
- 支持国际化;
- 支持消息机制;
- 支持统一的资源加载;
- 支持AOP功能;
container-context.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.xsd">
<bean class="com.dusk._3_container.SomeBean" id="someBean">
<property name="name" value="西门吹.牛"/>
</bean>
</beans>
测试类SpringContainerTest
public class SpringContainerTest {
//使用BeanFactory
@Test
public void testBeanFactory(){
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
System.out.println("-------------");
SomeBean bean = factory.getBean("someBean", SomeBean.class);
System.out.println(bean);
}
//使用ApplicationContext
@Test
public void testApplicationContext(){
//参数1:文件名称,参数2:本类名称
ApplicationContext ctx = new ClassPathXmlApplicationContext("App-Context.xml", SpringContainerTest.class);
System.out.println("------");
//参数1:配置id,参数2:bean字节码
SomeBean bean = ctx.getBean("someBean", SomeBean.class);
System.out.println(bean);
}
}
实体类SomeBean
@Setter@ToString
public class SomeBean {
private String name;
}
六.bean的实例化方式
bean的实例化方式:
- 构造器实例化(无参数构造器),最标准,使用最多。
- 静态工厂方法实例化:解决系统遗留问题
- 实例工厂方法实例化:解决系统遗留问题
- 实现FactoryBean接口实例化:实例工厂变种:
集成其他框架使用:SqlSessionFactoryBean和MapperFactoryBean
App-Context.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.xsd">
<!--<!–方式四:实现FactoryBean接口的方式–>
<bean id="someBean" class="com.dusk._4_instance.instance_factory.SomeBeanFactoryBean"/>-->
<!--方式三:实例工厂方法-->
<bean id="factory" class="com.dusk._4_instance.instance_factory.SomeBeanFactory"/>
<bean id="someBean" factory-bean="factory" factory-method="getObject"/>
<!-- 方式二:使用静态工厂方法获取bean对象
<bean id="someBean" class="com.dusk._4_instance.static_factory.SomeBeanFactory"
factory-method="getObject"/>-->
<!--<!–方式1:使用bean的无参构造器来实例化对象–>
<bean id="someBean" class="com.dusk._4_instance.common.SomeBean">
<property name="name" value="Dusk"/>
</bean>-->
</beans>
SomeBean类
@Setter@Getter@ToString
public class SomeBean {
public SomeBean(){
System.out.println("SomeBean");
}
private String name;
}
方式一.构造器实例化
<bean id="someBean" class="com.dusk._4_instance.common.SomeBean">
<property name="name" value="Dusk"/>
</bean>
方式二.静态工厂方法实例化
SomeBeanFactory类
//静态工厂
public abstract class SomeBeanFactory {
//获取Bean对象的方法是静态的
public static SomeBean getObject(){
System.out.println("静态复杂的初始化过程");
return new SomeBean();
}
}
<bean id="someBean" class="com.dusk._4_instance.static_factory.SomeBeanFactory"
factory-method="getObject"/>
方式三.实例工厂方法实例化
SomeBeanFactory
//SomeBeanFactory对象的实例化
public class SomeBeanFactory {
//获取Bean对象的方法不是静态的,需要改类的对象来调用
public SomeBean getObject(){
System.out.println("实例复杂的初始化过程");
return new SomeBean();
}
}
<bean id="factory" class="com.dusk._4_instance.instance_factory.SomeBeanFactory"/>
<bean id="someBean" factory-bean="factory" factory-method="getObject"/>
方式四.实现FactoryBean接口实例化
public class SomeBeanFactoryBean implements FactoryBean<SomeBean>{
//工厂方法
public SomeBean getObject() throws Exception {
System.out.println("实现接口复杂的初始化过程");
return new SomeBean();
}
public Class<?> getObjectType() {
return SomeBean.class;
}
public boolean isSingleton() {
return true;
}
}
<bean id="someBean" class="com.dusk._4_instance.instance_factory.SomeBeanFactoryBean"/>
测试类App
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {
@Autowired
private SomeBean someBean;
//传统方式
@Test
public void testOld() {
//1:找到静态工厂类
//2:调用工厂中的静态方法
/* SomeBean bean = SomeBeanFactory.getObject();
System.out.println(bean);*/
}
@Test
public void testStatic(){
System.out.println(someBean);
}
}
六.bean的作用域
<bean id="" class="" scope="作用域"/>
singleton: 单例 ,在Spring IoC容器中仅存在一个Bean实例 (默认的scope)
prototype: 多例 ,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean():不会在容器启动时创建对象
request: 用于web开发,将Bean放入request范围 ,request.setAttribute("xxx") , 在同一个request获得同一个Bean
session: 用于web开发,将Bean 放入Session范围,在同一个Session 获得同一个Bean
globalSession: 一般用于Porlet应用环境 , 分布式系统存在全局session概念(单点登录),如果不是porlet环境,globalSession 等同于Session
在开发中主要使用 scope="singleton"、 scope="prototype"
对于Struts2中的Action使用prototype类型,其他使用singleton
Spring容器会管理Action对象的创建,此时把Action的作用域设置为prototype.
七.初始化和销毁
SomeBean类
public class SomeBean {
private boolean flag;
public SomeBean(){
System.out.println("对象被创建");
}
public void init(){
flag = true;
System.out.println("对象初始化");
}
public void work(){
if (!flag){
throw new RuntimeException("对象未被初始化");
}
System.out.println("对象工作");
}
public void destroy(){
System.out.println("对象被销毁");
}
}
测试类App
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {
@Autowired
private ApplicationContext ctx;
@Test
public void test2(){
SomeBean bean = ctx.getBean("someBean", SomeBean.class);
bean.work();
}
}
App-Context.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.xsd">
<bean id="someBean" class="com.dusk._6_init_destroy.SomeBean"
init-method="init" destroy-method="destroy"/>
</beans>
八.依赖注入
-
对象注入的方式:
- 自动装配(了解)
- 手动注入(重点)
- 注解注入(重点)
-
通过哪些手动可以注入:
- 可以通过属性注入(setter方法).
- 通过构造器注入.
- 通过SpEL注入.
-
注入的时候,可有注入哪些类型的值.
- 简单类型(单一的值,使用value属性).
- 复合类型(JavaBean类型,使用ref属性)
- 集合类型(多个值,使用对应的集合标签)
-
使用setter注入(属性注入):
- 使用bean元素的子元素设置;
- 简单类型值,直接使用value赋值;
- 复合类型,使用ref赋值;
- 集合类型,直接使用对应的集合类型元素即可。
- spring通过属性的setter方法注入值;
- 在配置文件中配置的值都是string,spring可以自动的完成类型的转换
- 属性的设置值是在init方法执行之前完成的
- 改进spring的测试,直接在测试类里面注入需要测试的对象
- 使用bean元素的子元素设置;
简单类型
EmployeeDAOImpl类
@ToString
public class EmployeeDAOImpl implements IEmployeeDAO{
//简单类型
@Setter
private String dataSource;//模拟连接池
}
<!--把DAO组件交给Spring管理-->
<bean id="EmployeeDAO" class="com.dusk._7_di.dao.EmployeeDAOImpl">
<!--DI:简单类型-->
<property name="dataSource" value="druid"/>
</bean>
集合类型
MyCollection
@Setter
public class MyCollection {
private List<String> list;
private String[] arr;
private Set<String> set;
private Map<String,Object> map;
private Properties prop;
public String toString() {
return "MyCollection{" +
"\nlist=" + list +
", \narr=" + Arrays.toString(arr) +
", \nset=" + set +
", \nmap=" + map +
", \nprop=" + prop +
'}';
}
}
<!--属性注入:集合对象注入值-->
<bean id="coll" class="com.dusk._7_di.list.MyCollection">
<!--List集合注值-->
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<!--对array注值-->
<property name="arr">
<array>
<value>arr1</value>
<value>arr2</value>
</array>
</property>
<!--对Set注值-->
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
<!--对map集合注值-->
<property name="map">
<map>
<entry key="k1" value="v1"/>
<entry key="k2" value="v2"/>
</map>
</property>
<property name="prop">
<value>
k1=v1
k2=v2
</value>
</property>
</bean>
构造器注入
Employee
//使用属性注入->简单类型
@Setter@Getter@ToString
public class Employee {
private Long id;
private String name;
private BigDecimal salary;
private URL url;
private Class<?> clz;
public Employee() {
}
public Employee(Long id, String name) {
this.id = id;
this.name = name;
}
}
<!--构造器注值-->
<bean id="employeeC" class="com.dusk._7_di.Employee">
<constructor-arg value="10" name="id"/>
<constructor-arg name="name" value="Dusk"/>
</bean>
复合类型
EmployeeServiceImpl类
@ToString
public class EmployeeServiceImpl implements IEmloyeeService {
//依赖一个DAO
@Setter
private IEmployeeDAO employeeDAO;//复合类型
}
<bean id="employeeService" class="com.dusk._7_di.service.EmployeeServiceImpl">
<!--属性注入:复合类型,使用ref-->
<property name="employeeDAO" ref="EmployeeDAO"/>
</bean>
<!--把DAO组件交给Spring管理-->
<bean id="EmployeeDAO" class="com.dusk._7_di.dao.EmployeeDAOImpl">
<!--DI:简单类型-->
<property name="dataSource" value="druid"/>
</bean>
九.property place holder(属性占位符)
没有联网的需要导入命名空间的约束文件
db.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///struts2
jdbc.username=root
jdbc.password=admin
app-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
">
<!--使用Spring来读取db.properties文件
system-properties-mode忽略系统环境属性
-->
<context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>
<!--把Druid交给Spring来管理-->
<bean id="dateSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<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>
</beans>
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {
@Autowired
private DruidDataSource ds;
@Test
public void testDadaSource(){
System.out.println(ds);
}
}