spring框架介绍以及核心功能IOC DI
一.spring框架介绍
- spring是什么?
一。spring本身是一个轻量级框架集合
二。spring是一个企业级一站式的框架(spring boot, spring data,spring framework spring mvc)
三。spring又有很好的包容性,他为所有知名框架编写兼容jar,而且spring做很多杂活,例如兑现管理,事务管理,日志输出等,因此spring变得不可或缺
四。spring不排斥其他框架,与其他框架完美融合
ssh : spring struts hibernate
ssm: spring spring mvc mybaties
- spring有什么用
创建对象
1方便解耦 spring是一个对象工厂,内部可以帮助创建对象,以及对象的管理
例如:dbutils 工具类queryrunner = new queryrunner();
和hibernate 持久层框架:
SqlsessionFactoryBuilder
SqlsessionFactory
SqlSession
SqlSession.crud
spring 帮我们创建这些复杂的对象创建过程
spring-hiberbnate来创建对象
application.xml
<bean id=“sqlsession” class=“SqlSessionFactoryBuilder”
resource=“hibernate.xml”>
@Resource
SqlSession sqlsession;
spring 大工厂通用的创建对象模板
管理对象
例如:
class A
B b;
class B;
A a;
#### 特点支持事务 spring-tx
方便集成各种框架 hibernate、mybatis、struts等
对aop技术的支持 spring-aop,spring-aspects aopalliance aspectjweaver…
支持其他优秀框架
spring框架的组成
spring framework组成部分
spring web 控制器以及spring mvc
spring dao 持久层和事务
spring aop 面向切面
spring core container 核心IOC DI
spring test 测试
二.spring框架核心功能之IOC 基于XML文件配置
什么是IOC
```java ioc inversion of control 控制反转 将java对象的创建权利交给spring处理 有效解耦在配置文件中写bean名字,犬类路径名等。为反射提供环境,用无参构造创对象 #### 体验IOC 目的:将一个类的对象创建权利叫给spring 1. 步骤一: 导入spring的jar包:beans core context expression 2. 步骤二: 创建配置文件applicationContext.xml 3:配置文件编写 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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--对象的创建 通过反射创建对象--> <bean id="user" class="com.it.entity.User"></bean> <bean id="person" class="com.it.entity.Persion" scope="prototype"></bean> </beans> 4:. 步骤三:编写实体类,测试代码 //第一步获取容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //第二步单例获取bean Object user = context.getBean("user"); System.out.println(user)//com.it.entity.User@7ed7259e
三,详解配置文件的IOC
标签的使用
- name:为bean的名字。名字中可以有特殊符号,但是不可以有空格。
- id:为bean的名字,名字可以有特殊符号,包括空格
name和id的异同
相同点:
- 多个bean之间的id、name必须唯一
- 为bean起名时都可以包含特殊符号
- id 和bean不可以重名
不同点:
- id可以包含空格,name不可以有空格
区别测试:
<bean name="user^^^" class="com.it.entity.User"></bean> <bean id="user##" class="com.it.entity.User"></bean>
Object user = context.getBean("user^^^"); Object bean = context.getBean("user##"); System.out.println("user = " + user); System.out.println("bean = " + bean); result: user = com.it.entity.User@7fa98a66 bean = com.it.entity.User@15ff3e9e
<bean name="user ^^^" class="com.it.entity.User"></bean> <bean id="user ##" class="com.it.entity.User"></bean>
//Object user = context.getBean("user ^^^"); Object bean = context.getBean("user ##"); //System.out.println("user = " + user); System.out.println("bean = " + bean); result: bean = com.it.entity.User@7fa98a66 Object user = context.getBean("user ^^^"); //Object bean = context.getBean("user ##"); System.out.println("user = " + user); //System.out.println("bean = " + bean); result: NoSuchBeanDefinitionException: No bean named 'user ^^^' available
- class:bean 的全类路径名,spring拿到通过反射来用无参构造创建对象 而且只用无参构造创建对象
测试无参创建对象:覆盖无参构造
/*public User() { }*/ public User(int age, String name, String gender) { this.age = age; this.name = name; this.gender = gender; } <bean id="user" class="com.it.entity.User"></bean>//此处报红,显示no such constructor method
scope:
- singleton:单例
默认测试:
Object user = context.getBean("user");Object user1 = context.getBean("user");System.out.println(user);System.out.println(user1); com.it.entity.User@7fa98a66 com.it.entity.User@7fa98a66 相同:证明多次获取的同一个bean
- prototype 多例
多例测试:
<bean id="user" class="com.it.entity.User" scope="prototype"></bean> Object user = context.getBean("user"); Object user1 = context.getBean("user"); System.out.println(user); System.out.println(user1); com.it.entity.User@7334aada com.it.entity.User@1d9b7cce 不一样:说明多次获取不同的bean
lazy-init:
默认测试:
System.out.println("获取前"); Object user = context.getBean("user"); System.out.println(user); constructor---------- 获取前 com.it.entity.User@7fa98a66 可见在获取之前就已经构造初始化了 修改: <bean id="user" class="com.it.entity.User" lazy-init="true"></bean> 获取前 constructor---------- com.it.entity.User@62150f9e 可见:在获取后才构造初始化的 多例模式下:始终是懒加载
- init-method 和destroy-method:
// 初始化方法 public void init(){ System.out.println("User.init"); } //销毁方法 public void destrory(){ System.out.println("User.destrory"); } constructor---------- User.init 获取前 com.it.entity.User@7fa98a66 初始化方法在构造器之后执行 销毁方法没有执行 关闭容器:发现销毁方法执行了 钩盖成多利模式:发现无论关闭容器与否,都不执行销毁方法
四 springIOC容器
1:获取容器传入配置文件
spring ioc包含在spring-context中
ioc容器的总接口 ApplicationContext
因此需要借助实现类才可以获取容器
- FileSystemXmlApplicationContext 磁盘绝对路径
- ClassPathXmlApplicationContext 项目相对路径寻找配置文件
注意:
- 在编译后查看文件是否被加载进target里面
- 检查配置文件名字是否正确
2:获取Bean
容器名.getBean(String name) Object
容器名.getBean(String name,aClass); Entity
3:静态工厂
对象是通过工厂模式创建出来的
public ststic User createUser(){ return new User("uuu",11); }
<!--静态工厂--> <bean id="user2" class="com.it.entity.UserFactory" factory-method="createUser"></bean>
result:
argument constructor 333333
argument constructor 333333
User{name=‘hfh’, age=12}
User{name=‘uuu’, age=11}4:非静态工厂模式
创建对象的方式是非静态的
创建非静态工厂
创建对象
<!--非静态工厂先创建工厂bean 然后引用工厂,用工厂的方法创建bean--> <bean id="factory" class="com.it.entity.UserFactory"></bean> <bean id="user3" factory-bean="factory" factory-method="createUser"></bean>
result:
argument constructor 333333
User{name=‘uuu’, age=11}
注意 :在配置文件中只要写了完整的创建bean的配置,构造器就会执行,即使你不在业务代码中调用它
五 注入 Di
回顾:spring使用xml进行ioc 控制反转 使用spring进行对象创建和管理
spring是一个大工厂,可以帮我们创建对象和管理
spring xml 格式的DI有两个核心前提
1:如果spring IOC 容器的对象需要DI的另一个对象,要求他们都应该被IOC管理
2:xml 进行对象的DI 时候要求对象必须要设置属性的getter|setter方法
1. 基本注入
基本类型|值类型的属性 name value 形式
<bean id="person" class="com.it.entity.Person"> <constructor-arg name="age" value="12"></constructor-arg><!--任何类型都被写成字符串类型,但是如果对应类型写错会编译通不过 例如 int类型的age写成ABC --> <constructor-arg name="name" value="何发海"></constructor-arg> </bean>引用类型
2.引用类型 name ref 要求:ref的值应该由容器管理
<!--引用类型 构造方式--> <bean id="person" class="com.it.entity.Person"> <constructor-arg name="age" value="12"></constructor-arg> <constructor-arg name="name" value="何发海"></constructor-arg> <constructor-arg name="doctor" ref="doctor1"></constructor-arg> </bean> <!--引用类型--> <bean id="doctor1" class="com.it.entity.Doctor"> <constructor-arg name="age" value="12"></constructor-arg> <constructor-arg name="username" value="jklh"></constructor-arg> </bean> <!--属性方式注入方式--> <bean id="person1" class="com.it.entity.Person"> <property name="age" value="12"></property> <property name="name" value="hfh"></property> <property name="doctor" ref="doctor"></property> </bean> <bean id="doctor" class="com.it.entity.Doctor"> <property name="age" value="43547"></property> <property name="username" value="bbbb"></property> </bean>
注意:基本类型或者值类型使用value赋值
引用类型使用ref引用已经存在的IOC对象id名
案例:
有一学生类:姓名、性别、地址对象、学校对象
地质类:省 市 县 使用构造函数赋值
学校类: 学校名 学校占地面积 学生人数
打印学生对象打印全信息
<bean id="student" class="com.it.entity.Student"> <property name="age" value="12"></property> <property name="address" ref="address"></property> <property name="school" ref="school"></property> <property name="sname" value="珍君"></property> </bean> <bean id="address" class="com.it.entity.Address"> <constructor-arg name="city" value="北京"></constructor-arg> <constructor-arg name="coiuntry" value="昌平"></constructor-arg> <constructor-arg name="province" value="河北"></constructor-arg> </bean> <bean id="school" class="com.it.entity.School"> <constructor-arg name="area" value="123"></constructor-arg> <constructor-arg name="cName" value="中国民用航空飞行学院"></constructor-arg> <constructor-arg name="count" value="120000"></constructor-arg> </bean>
容器三级缓存:先ref引用 后再创建Bean 先解析到bean 后赋值
p命名空间注入
- 简单属性注入
步骤一:引入p命名空间约束
xmlns:p="xmlns:p=“http://www.springframework.org/schema/p”"
步骤二:在bean标签内部属性的位置引入p命名空间进行属性注入
<!--p命名空间注入属性--> <bean id="student" class="com.it.entity.Student" p:age="55" p:sname="珍君" p:address-ref="address" p:school-ref="school"> </bean> <bean id="address" class="com.it.entity.Address" p:city="上海" p:coiuntry="昌平" p:province="宁夏"> </bean>
构造器简单c命名空间注入
<!--c 构造器简化命名空间注入属性--> <bean id="school" class="com.it.entity.School" c:area="12345" c:cName="中国民用航空飞行学院" c:count="123456"> </bean>
引入外部配置文件注入(properties配置文件)
有时候我们需要在外部定义一些properties文件配置,需要引入到springIOC容器中
步骤一:添加context命名空间:xmlns:context=“http://www.springframework.org/schema/context”
步骤二:引入外部配置文件:<context:property-placeholder location=“classpath:db.properties”></context:property-placeholder>
步骤三 在bean标签的value属性中用属性value=${properties里的key}
<!--第二步引入properties--> <context:property-placeholder location="classpath:db.properties"></context:property-placeholder> <bean id="jdbc" class="com.it.entity.Jdbc"> <property name="password" value="${password}"></property> <property name="url" value="${url}"></property> <property name="username" value="${username}"></property> </bean>
问题: 一个springioc的xml配置中,可能会引入多个专项properties配置文件!
默认情况只有第一个生效!解决:
既然框架的设计者在设计约束的时候!允许出现多个property标签,就证明
可以次可以导入多个标签!
只不过默认只支持第一个!解决方案1:
在每个标签内部添加 ignore-unresolvable=“true”解决方案2: location值的时候!使用,进行分开引入! location="classpath:jdbc.properties,classpath:boot.properties"
classpath和classpath*:的区别classpath会引入resources再有目录的文件 classpath只会引入resources里面的文件
注意 :properties里面只能申明字符串类型,基本类型
spring boot yaml 里面可以申明数组集合 和map
spring expression表达式的注入
#{}
1:获取其他bean 的属性值 id名.属性名
<bean id="user" class="com.it.domain.User"> <property name="name" value="${url}"></property> <property name="age" value="${aaa}"></property> </bean> <!--sxpression 表达式--> <!--获取其他bean的属性值--> <bean id="user2" class="com.it.domain.User"> <property name="age" value="#{user.age}"></property> <property name="name" value="#{user.name}"></property> </bean>
2:引入其他bean的函数 id名.函数名字
<!--调用函数--> <bean id="user3" class="com.it.domain.User"> <property name="name" value="#{user.getAge()}"></property> </bean>
3:引入java内置函数#{T(内置函数名).函数方法()}
<!--调用内置函数--> <bean id="user4" class="com.it.domain.User"> <property name="age" value="#{T(Math).round(T(Math).random()*100)}"></property> </bean>
4:基本+ - * / % 运算
<bean id="user5" class="com.it.domain.User"> <property name="name" value="#{'${aaa}'+789}"></property> </bean>
5:复杂类型数据属性的注入
<bean id="car" class="com.it.domain.Car"> <!--数组--> <property name="color"> <array> <value>白色</value> <value>黄色</value> <value>黑色</value> <value>橘色</value> <value>咖啡色</value> </array> </property> <!--结合--> <property name="names"> <list> <value>vklsdjf</value> <value>vklsdjf</value> <value>vklsdjf</value> <value>vklsdjf</value> </list> </property> <property name="map"> <map> <entry key="fsd" value="57525"></entry> <entry key="gf" value="fsbvsffd"></entry> <entry key="fsd" value="8278"></entry> <entry key="fsd" value="27"></entry> </map> </property> </bean>
六注解形式的IOC DI
注解的优势
- 注解更加简单方便
- 可以进行批量操作,扫描,以包为单位
- 注解在进行属性注入时不需要有getter setter 方法
使用场景
- 注解通常在自定义的类上使用
- xml配置通常配置第三方类
三个基本注解
@Repository
@Controller
@Service
注明value=“类名首字母小写” bean让扫描扫描到此处利用反射创建对象
@PropertySource(“classpath:info.properties”) //引入外部配置文件
@Value(key=“值”)
@Value("${gvdsf}") $ 引入值 “#{}” expresson表达式引入值注入
@Autowired()//自动装配
@Reource(name=“jbkfl”)//区分同名
spring IOC 的使用
使用注解形式的ioc操作需要在类上添加特殊的注解,以及注解需要被扫描
步骤一:类上面加上注解@Component(在ioc中的id值如果不写就会默认类名第一个字母小写)==创对象
步骤二:指定生成的模式@Scope(scopeName=“singleTon”|propotype)
步骤三:扫描在xml文件中<context:component-scan base-package=“包,包,包”
注意:包名越精确越好,效率越高
spring DI
2. 基本类型注入(基本数据类型|值类型|)
@Value() 注入 @PropertySource("")引入外部配置
3. 引用类型注入
@Autowirred() 在变量上面 可根据变量类型查找
如果变量是接口,找到接口早ioc中的实现类对象
问题 如果有多个相同类型他们怎么找
expected single matching bean but found 2: serviceImpl1,serviceImpl2 at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:176)
方案:
指定具体的实现类
@Autowired
@Qualifier(“实现类名字”)
方案二:
@Reource(name=“实现类名字”)
注意:如果出现no bean named ‘xxx’ available
- 名字写错
- 没加注解
- 没有扫描
七 spring使用配置类的形式进行配置
spring4以后提供一种配置类的形式进行类替代xml配置文件
步骤一:申明一个配置类
@Configeration //将一个类变成配置类 替代xml文件 @ComponentScan("com.it") //扫描 public class Configer{ }
步骤二 初始化容器
ApplicationContext context = new AnnotationConfigApplicationContext(配置类.class);
八spring使用test功能搭建测试环境
junit
spring-test
主要功能视同spring去加载配置文件,不需要自己动手去常见内容进行文件的加载,因为
我们使用注解不需要自己获取容器中的bean
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml")//告诉spring去初始化指定的配置文件 public class TestA{ @Autowired private User user; @Test public void test(){ } }