一、Spring入门案例
Spring概念: Spring框架由Rod Johnson开发,2004年发布了Spring框架的第一版。Spring是一个从实际开发中抽取出来的框架,因此它完成了大量开发中的通用步骤,留给开发者的仅仅是与特定应用相关的部分,从而大大提高了企业应用的开发效率。
Spring优点:
-
低侵入式设计,代码的污染极低。
-
独立于各种应用服务器,基于Spring框架的应用,可以真正实现Write Once,Run Anywhere的承诺。
-
Spring的IoC容器降低了业务对象替换的复杂性,提高了组件之间的解耦。
-
Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用。
-
Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问。
-
Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部。
Spring核心技术: IoC和AOP,能够实现类之间、模块之间的解耦合。
IoC: IoC(控制反转)就是依赖倒置原则的一种代码设计思路。就是把原先在代码里面需要实现的对象创建、对象之间的依赖,反转给容器来帮忙实现。
Spring IOC容器通过xml,注解等其它方式配置类及类之间的依赖关系,完成了对象的创建和依赖的管理注入。实现IOC的主要设计模式是工厂模式。
IoC技术实现: DI是IoC的技术实现, DI(Dependency Injection)依赖注入,只需要在程序中提供要使用的对象的名称就可以,至于对象在容器中如何创建、赋值、查找都由容器内部实现。Spring是使用DI实现了IoC的实现,Spring底层创建对象使用的是反射机制。
使用IoC,由Spring创建对象实现步骤:
1. 创建maven项目
2. 加入maven的依赖:Spring的依赖,junit依赖
<dependencies>
<!--Spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--单元测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
3. 创建类(接口和实现类):创建类和没有使用框架一样,就是普通类。
4. 创建Spring需要使用的配置文件,声明类信息,这些类交由Spring创建和管理
Spring的配置文件:
- beans:是根标签,Spring把java对象称为bean。
- spring-beans.xsd:是约束文件,和mybatis指定 .dtd是一样的。
告诉Spring创建对象:
首先要声明bean,一个bean标签声明一个对象,就是告诉Spring要创建某个类的对象。
id: 对象的定义名称,唯一值。Spring就是通过这个名称找到对象。
class: 类的全限定名(不能是接口,因为Spring是反射机制创建对象,必须是类)
<bean id="someServiceImpl" class="com.cn.spring.serviceImpl.SomeServiceImpl">
</bean>
5. 测试Spring创建的对象
使用由Spring创建的对象:
-
指定Spring配置文件的名称
String config="ApplicationContext.xml";
-
创建表示Spring容器的对象,ApplicationContext;
- ApplicationContext就是表示Sprring容器,通过容器获取对象;
- ClassPathXmlApplicationContext:表示从类路径中加载Spring的配置文件(在target下面读取指定配置文件,读取到声明的bean时会根据类的全限定路径找到该类然后调用该类的无参构造(spring默认调用无参构造)创建该类的对象,并将创建好的对象放到容器中);
- Spring默认创建对象的时间:在创建spring的容器时,会创建配置文件中的所有的对象。
ApplicationContext ac=new ClassPathXmlApplicationContext(config);
从容器中获取对象:
注意:getBean(“配置文件中bean的id值”);因为getBean返回值类型是Objecct类型的所以需要强转;
SomeService ss=(SomeService) ac.getBean("someServiceImpl");
测试结果:
package com.cn.spring;
import com.cn.spring.service.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void test01(){
String config="ApplicationContext.xml";
ApplicationContext ac=new ClassPathXmlApplicationContext(config);
SomeService ss=(SomeService) ac.getBean("someServiceImpl");
ss.doSome();
}
}
二、Spring的DI
DI:依赖注入,表示创建对象,给属性赋值。
DI的实现有两种:
- 在Spring的配置文件中,使用标签和属性完成,叫做基于XML的DI实现。
- 使用Spring中的注解,完成属性赋值,叫做基于注解的DI实现。
DI语法分类:
- set注入(设值注入):spring调用set方法,在set方法可以实现属性的赋值。
- 构造注入:spring调用类的有参构造,创建对象,在构造方法中完成赋值。
一、基于XML的DI
1.1、set注入
a、简单类型的set注入
<bean id="XXX" class="类权限定名">
<!--注意:一个property只能给一个属性赋值-->
<property name="属性名字" value="此属性值"/>
</bean>
b、引用类型的set注入
<bean id="myStudent" class="类全限定名">
<property name="引用类型属性名" ref="指向引用类型声明bean时的id值"/>
</bean>
<bean id="mySchool" class="类全限定名">
<property name="tel" value="130000000"/>
</bean>
测试结果:
1.2、构造注入
构造注入:spring调用类的有参构造,在创建对象的同时在构造方法中给属性赋值;
public Student() {}//spring默认创建对象调用的是无参构造
/**
* 创建有参构造完成属性的赋值
* @param name
* @param age
* @param school
*/
public Student(String name, int age, School school) {
/*给属性赋值*/
this.name = name;
this.age = age;
this.school = school;
System.out.println("----------student有参数构造方法---------");
}
构造注入使用<constructor-arg>
标签;
<constructor-arg>
标签: 一个<constructor-arg>
标签表示构造方法一个参数,如果构造方法有多个参数则需要多个<constructor-arg>
标签。
<constructor-arg>
标签属性:
name:构造方法形参名;
index:构造方法形参位置,参数从左往右位置是0、1、2的顺序;
velue:属性值,构造方法的属性是简单类型的则使用velue;
ref:属性值,构造方法的属性是引用类型的则使用ref;
<bean id="myStudent01" class="com.cn.spring.testDI01.testDI.Student">
<constructor-arg value="李四"/>
<constructor-arg value="23"/>
<constructor-arg ref="mySchool01"/>
</bean>
<bean id="mySchool01" class="com.cn.spring.testDI01.testDI.School">
<constructor-arg value="清华大学"/>
<constructor-arg value="010-1111111"/>
</bean>
测试结果:
引用类型的自动注入:
Spring根据某些规则可以给引用类型进行赋值,不用再手动给引用类型赋值了;赋值方式:byName和byType
1、byName(按名称注入): java类中引用类型和spring容器(配置文件)中bean标签的id名一致,且数据类型一致,这样spring就会给bean标签中的引用类型赋值。
语法:
<bean id="xxx" class="yyy" autowire="byName">
简单类型属性赋值
</bean>
配置文件配置:
<bean id="myStudent01" class="com.cn.spring.testDI01.testDI.Student" autowire="byName">
<property name="name" value="王五"/>
<property name="age" value="18"/>
</bean>
<bean id="school" class="com.cn.spring.testDI01.testDI.School">
<property name="name" value="理工大学"/>
<property name="tel" value="010-7777777"/>
</bean>
测试结果:
2、byType(按类型注入): java类中引用类型的数据类型和spring容器中(配置文件)bean的 class属性是同源关系,这样的bean能够赋值给引用类型。
同源关系:
a、java类中引用类型的数据类型和容器中的bean的class值是一样的;
b、java类中引用类型的数据类型和容器中的bean的class的值是父子类关系的;
c、java中引用了欸行的数据类型和容器中的bean的class的值是接口与实现类的关系的;
语法:
<bean id="xxx" class="yyy" autowire="byType">
简单类型属性赋值
</bean>
配置文件配置:
<bean id="myStudent01" class="com.cn.spring.testDI01.testDI.Student" autowire="byType">
<property name="name" value="赵六"/>
<property name="age" value="18"/>
</bean>
<bean id="school" class="com.cn.spring.testDI01.testDI.School">
<property name="name" value="人民大学"/>
<property name="tel" value="010-8888888"/>
</bean>
测试结果:
二、基于注解的DI:
通过注解完成java对象的创建和属性赋值;
使用注解的步骤:
1、加入maven依赖 spring-context,加入context的同时会自动加入spring-aop的依赖;使用注解必须使用spring-aop依赖。
2、在类中加入spring注解(多个不同功能的注解);
3、在spring配置文件中,加入一个组件扫描器的标签,说明注解在项目中的位置;
创建类: 类上面加上@Component注解并指定名称
@Component 创建对象的,相当于的功能
属性:value 就是对象的名称,也就是bean的id名;
value的值是唯一的,创建的对象在整个spring中只有一个;
位置:在类的上面;
创建的对象放在spring的容器中;
//使用value指定名称
//@Component(value="myStudent")
//也可以省略value
//@Component("myStudent")
//也可以不指定名称,由spring指定默认的名称(注意:默认的名称就是类名首字母小写,使用getBean的时候就写这个名称)
@Component
public class Student {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
在配置文件中指定组件:
声明组件扫描器(component-scan),组件就是java对象,
base-package="":指定注解在项目中的包名。
component-scan工作方式:spring会扫描遍历base-package指定的包,把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象或者给属性赋值。
<context:component-scan base-package="com.spring.di.anno"/>
指定多个包的方式:
1、指定多次组件扫描器,指定不同的包;
<context:component-scan base-package="com.spring.di.anno"/>
<context:component-scan base-package="com.spring.di.anno01"/>
......
2、使用分隔符( ; 或 , )分割多个包名
<context:component-scan base-package="com.spring.di.anno;com.spring.di.anno01"/>
3、指定父包(扫描器的特点是扫描当前包以及子包中所有的类)
<context:component-scan base-package="com.spring.di"/>
创建测试类进行测试:
public class TestAnno {
@Test
public void testAnno(){
String config="applictionContext.xml";
ApplicationContext ac=new ClassPathXmlApplicationContext(config);
Student sd= (Student) ac.getBean("myStudent");
System.out.println(sd);
}
}
测试结果:
Spring中和@Component功能一致,创建对象的注解还有:
1、@Repository(放在持久层上面的):放在dao的实现上面,表示创建dao对象,dao是访问数据库的;
2、@Service(放在业务层上面的):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的。
3、@Controller(放在控制器上面的):放在控制器(处理器)上面,创建控制器对象,能够接受用户请求的参数,显示请求处理的结果。
以上这三个注解使用语法和@Component是一样的,但是这三个注解还有额外的功能。
@Repository、@Service、@Controller这三个注解是给项目分层用的。
简单类型的属性赋值@Value
@Value简单类型的赋值
属性:value,是String类型的,表示简单类型的属性值;
位置:1、用在属性定义的上面,无需set方法;
2、用在set方法的上面;
测试1:
测试2:
引用类型的属性赋值@Autowired
@Autowired:spring框架提供的注解,实现引用类型的赋值。
spring中通过注解给引用类型赋值,实现的原理是自动注入,支持byName,byType;
@Autowired:默认使用的是byType自动注入。
位置:1、引用类型定义上面(推荐使用),无需set方法;2、set方法上面(不推荐使用);
@Autowired
private School school;
测试:
自动注入使用byName:
@Autowired默认使用的是byType自动注入,如果要使用byName自动注入需要做如下步骤:
1、在属性上面加@Autowired注解;
2、在属性上面加@Qualifier(value=“bean的id”):表示指定名称的bean完成赋值;
注意:
测试:
@Autowired注解的required属性:
@Autowired(required = false/true)
required:是一个boolean类型的,默认为true;
required = true:表示引用类型赋值失败,并终止执行;
required = false:表示引用类型赋值失败,程序正常执行,引用类型为null
一般在项目中使用默认的true,当赋值失败的时候直接抛错可以更准确的定位到错误位置;
@Resource注解
@Resource注解来自jdk中的注解,spring框架提供了对这个注解的支持,可以使用它给引用类型赋值。
@Resource使用的也是自动注入原理,支持byName和byType,默认是byName;
位置:1、在引用类型的定义上面,无需set方法(推荐使用);2、在set方法上(不推荐使用)
@Resource在自动注入的时候默认为byName,当使用byName赋值失败的时候则自动使用byType进行赋值;
如果@Resource只是用buName则需要指定name:@Resource(name=“bean的id”)