1.1、Spring概述
spring框架的核心:
一:控制饭庄,反转资源控制方向,将自己创建资源转变为向环境索取资源,享受资源的注入。
二:AOP--面向切面编程,java的继承机制是纵向继承机制,这不利于程序的封装,而面向切面编程(AOP)是横向抽取机制的。
1.2、IOC
1.2.1、IOC容器
IOC思想:说白就是反转控制,将对象的控制权反转给IOC容器
DI:依赖注入,说白了就是赋初始值,组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器 的资源注入
1.2.2、IOC容器在Spring中的实现
IOC容器有两种实现方式:
①BeanFactory,是Spring内部使用的接口,面向Spring开发者。
②ApplicationContext,BeanFactory的子接口,是专门为开发者提供
内部类的继承关系
注意:
ClassPathXmlApplicationContext是通过读取类路径下的 XML 格式的配置文件创建 IOC 容器 对象
FileSystemXmlApplicationContext通过文件系统路径读取 XML 格式的配置文件创建 IOC 容 器对象(一般不用,可移植性比较差)
1.2.3、基于XML方式管理Bean
实验一:简单入门:
创建Spring配置文件:
配置Bean标签:
其中id是唯一表示,class设置bean所对应类型的全类名。
下面是测试文件
注意:resource和java最终会被加载到同一个路径下,所以写类名时可以不用写全类名。
通过Bean标签的id属性来获取对象,最后调用sayHello()方法,获取的对象时Object类型,要进行向下转型。
注意点:IOC底层是通过反射来进行的,因为反射的时候就是调用空参构造器,那么对于类HelloWorld而言一定要有空参构造器,否则会报错误。
实验二:获取Bean对象的三种方式
方式一(根据Bean的id来获取对象):由于 id 属性指定了 bean 的唯一标识,所以根据 bean 标签的 id 属性可以精确获取到一个组件对象。
方式二:根据类型获取IOC容器,但是这是有条件的:当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个,这也是实际开发中最最常用的方式,因为实际开发中只会出现一个Bean标签。
方式三:根据id和类型
注意:根据id和类型获取一级根据id获取,不用向下转型
注意:一个java类对应一个Bean标签,对应一个组件。
扩展:
如果组件类实现了接口,根据接口类型可以获取得到Bean
如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型不可以获取 bean
实验三:依赖注入之setter注入:
所谓依赖注入,含义就是为属性对象赋值的过程,主要分为setter注入和构造器注入。
property标签:为属性赋值,调用的是setXXX方法,为属性赋值,name指定属性名,value属性用于指定属性名。
实验四:依赖注入之构造器注入:
构造器注入的基本条件是要求java类中有对应的构造器,之后配置Bean就可以了
上图中value属性用于指定给哪个变量进行赋值,name属性专门指定赋值的属性是age属性,这是为了防止java类中有两个相同类型的构造器(最后一个参数都是数值类型的)。
实验五:特殊值处理
①字面量的处理,这个在上面已经讨论过了
②null值的处理
注意:不可以直接在value属性中设置,null属性,这样会解析成为"null"字符串,如下面所示
<constructor-arg > <null/> </constructor-arg>
②xml实体,所谓的xml实体,由于配置文件是xml文件,因此不可以对<>等关键词进行赋值,
方法一:要用实体来进行替代,如下面所示:
就是<李四>
方法二:用CD Data区,CD Data区中的数据会被原样解析,如下所示
CD Date区在idea中的快捷键是CD(一定要大写)
实验六:为类类型的属性进行赋值
注意:对一对应对象,对多对应集合(再次强调),下面的代码中,在Student对象中有一个Clazz类的类型对象。
三种方式:
方式一:引用外部已经声明的Bean
<bean id="Clazz" class="com.atguigu.spring.pojo.Clazz"> <property name="cname" value="牛逼的人"></property> <property name="cid" value="1111"></property> <property name="students" ref="studentList"> </property> </bean> <bean id="studentFive" class="com.atguigu.spring.pojo.Student"> <property name="sid" value="1004"></property> <property name="name" value="赵六"></property> <property name="gender" value="男"></property> <property name="age" value="26"></property> <property name="clazz" ref="Clazz"></property> </bean>
方式二:内部bean进行处理
<bean id="studentFive" class="com.atguigu.spring.pojo.Student"> <property name="sid" value="1004"></property> <property name="name" value="赵六"></property> <property name="gender" value="男"></property> <property name="age" value="26"></property> <property name="clazz"> <bean id="clazzInner" class="com.atguigu.spring.pojo.Clazz"> <property name="cid" value="1112"></property> <property name="cname" value="远大前程"></property> </bean> </property>
</bean>
方式三:通过级联的方式进行
<bean id="studentFive" class="com.atguigu.spring.pojo.Student"> <property name="sid" value="1004"></property> <property name="name" value="赵六"></property> <property name="gender" value="男"></property> <property name="age" value="26"></property> <property name="clazz" ref="Clazz"></property> <!-- 使用级联的方式,但是需要提前为class属性进行赋值或者进行实例化,用的并不是很多--> <property name="clazz.cid" value="1112"></property> <property name="clazz.cname" value="远大前程"></property> </property>
</bean>
注意:使用级联的方式是用的最少的,因为不一定知道具体要赋值的类的对象。
实验七:为数组类型属性赋值
为Student类型中添加属性:
对Bean进行配置
<bean id="studentFive" class="com.atguigu.spring.pojo.Student"> <property name="sid" value="1004"></property> <property name="name" value="赵六"></property> <property name="gender" value="男"></property> <property name="age" value="26"></property> <bean id="clazzInner" class="com.atguigu.spring.pojo.Clazz"> <property name="cid" value="1112"></property> <property name="cname" value="远大前程"></property> </bean> </property> <property name="hobby"> <array> <value>唱</value> <value>跳</value> <value>rap和篮球</value> </array> </property> </bean>
通过Array标签可以对数组类型的属性赋予初始值
实验八:为集合类型的属性赋值
在Class类中添加属性:
配置Bean
方式一:同数组类型一样
<bean id="Clazz" class="com.atguigu.spring.pojo.Clazz"> <property name="cname" value="牛逼的人"></property> <property name="cid" value="1111"></property> <property name="students"> <!-- 这是进行赋值的方式一--> <list> <ref bean="studentOne"></ref> <ref bean="studentTwo"></ref> <ref bean="studentThree"></ref> </list> </property> </bean>
方式二:应用utils约束
<bean id="Clazz" class="com.atguigu.spring.pojo.Clazz"> <property name="cname" value="牛逼的人"></property> <property name="cid" value="1111"></property> <property name="students" ref="studentList"> </property> </bean> <!-- 配置一个集合类型的bean,然后使用utils类型的约束 --> <utils:list id="studentList"> <ref bean="studentOne"></ref> <ref bean="studentTwo"></ref> <ref bean="studentThree"></ref> </utils:list>
实验九:为Map类型的属性赋值
方式一:通过Map标签进行处理,运用子标签entry对key和value两个属性进行赋值
在Student中添加属性:
在xml中配置属性:
方式二:运用utils约束
实验十:使用命名空间
这也是一个约束
实验十一:引入外部属性文件
首先引入外部属性文件
<context:property-placeholder location="jdbc.properties"> </context:property-placeholder> 引入外部属性文件以后,就可以根据${}的方式访问属性名字 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value='${jdbc.driver}'></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean>
实验十二:Bean的作用域
spring可以通过配置bean标签的scope属性来指定bean的作用域,具体如下面所示:
singleton表示是单例模式,propotype表示不是单例模式
实验十三:Bean的生命周期
bean对象创建(调用无参构造器)
给bean对象设置属性 bean对象初始化之前操作(由bean的后置处理器负责)
bean对象初始化(需在配置bean时指定初始化方法)
bean对象初始化之后操作(由bean的后置处理器负责)
bean对象就绪可以使用 bean对象销毁(需在配置bean时指定销毁方法)
IOC容器关闭
实验十四:FactoryBean
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个 FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是 getObject()方法的返回值。
具体如下所示:
配置的Bean
通过上面getObject方法得到的返回值,返回我要的bean对象
实验十五:基于XML自动装配Bean
根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类 型属性赋值。
自动装配主要有两种方式:byType(主要使用方式,根据类型自动装配Bean对象,要求Bean标签中有且只有一个类型对应的Bean)和byName(根据名称自动寻找Bean对象,这时候默认寻找的id是所要赋值的属性名,通过属性名进行配置)
<bean id="userControl" class="com.atguigu.spring.control.UserControl" autowire="byType"> <!-- <property name="userService" ref="userService"></property>--> </bean> <bean id="userService" class="com.atguigu.spring.service.impl.UserServiceImpl" autowire="byType"> <!-- <property name="userDao" ref="userDao"></property>--> </bean> <bean id="userDao" class="com.atguigu.spring.dao.impl.UserDaoImpl"> </bean>
1.2.4 基于注解管理Bean
实验一:标记和扫描
首先,注解本身是一个标记,具体执行要交给框架底层进行实行,Spring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注 解进行后续操作。
标识足交所使用的注解:
@Component:将类标识为普通组件
@Controller:将类标识为控制层组件
@Service:将类标 识为业务层组件
@Repository:将类标识为持久层组件
这四个注解本质上是一样的,只不过未了程序员容易理解,所以用了四个注解
扫描组件(初始的扫描方式):
<context:component-scan base-package="com.atguigu.spring"> </context:component-scan>
这里是根据包进行扫描,表示扫描com.atguigu,spring 下面的所有类
扫描组件的两个标签(exclude和include标签):
<context:component-scan base-package="com.atguigu.spring"> <!-- 这是根据注解进行排除--> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!-- 这是根据类的类型进行排除--> <context:exclude-filter type="assignable" expression="com.atguigu.spring.control.UserControl"/> </context:component-scan>
这个扫描标签有两个属性
include标签表示只扫描指定的组件,但是必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类。
重点:
@Autowired注解的原理
* a>默认通过byType的方式,在IOC容器中通过类型匹配某个bean为属性赋值
* b>若有多个类型匹配的bean,此时会自动转换为byName的方式实现自动装配的效果
* 即将要赋值的属性的属性名作为bean的id匹配某个bean为属性赋值
* c>若byType和byName的方式都无妨实现自动装配,即IOC容器中有多个类型匹配的bean
* 且这些bean的id和要赋值的属性的属性名都不一致,此时抛异常:NoUniqueBeanDefinitionException
* d>此时可以在要赋值的属性上,添加一个注解@Qualifier
* 通过该注解的value属性值,指定某个bean的id,将这个bean为属性赋值
*