目录
框架,即framework。其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。
框架是对特定应用领域中的应用系统的部分设计和实现的整体结构。
Spring概述
1)Spring是一个开源框架
2)Spring为简化企业级开发而生,使用Spring,JavaBean就可以实现很多以前要靠EJB才能实现的功能。同样的功能,在EJB中要通过繁琐的配置和复杂的代码才能够实现,而在Spring中却非常的优雅和简洁。
3)Spring是一个IOC(DI)和AOP容器框架。
4)Spring的优良特性
① 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
② 依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。
③ 面向切面编程:Aspect Oriented Programming——AOP
对于OOP的补充
④ 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
⑤ 组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
⑥ 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。
5)Spring模块
搭建Spring运行时环境
首先在module下创建一个source类型的文件夹 ,命名为config
1)加入JAR包
① Spring自身JAR包:spring-framework-4.0.0.RELEASE\libs目录下
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELE2ASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
② commons-logging-1.1.1.jar
最后将所有这些jar包add as library
2)在Spring Tool Suite工具中通过如下步骤创建Spring的配置文件
① File->New->Spring Bean Configuration File
② 为文件取名字 例如:applicationContext.xml
简单测试:通过Spring创建对象
1、先创建一个Person类
package com.spring.mod;
public class Person {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
public Person() {
}
}
2、配置Spring文件
<?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元素定义一个由IOC容器创建的对象 -->
<!-- class属性指定用于创建bean的全类名 -->
<!-- id属性指定用于引用bean实例的标识 -->
<bean id="person" class="com.spring.mod.Person">
<!-- 使用property子元素为bean的属性赋值 -->
<property name="id" value="1001"></property>
<property name="name" value="郭超"></property>
</bean>
<!--一个bean就相当于于一个Person对象-->
</beans>
3、测试:通过Spring的IOC容器创建Student类实例
public class TestBySpring {
public static void main(String[] args) {
//初始化容器
//创建IOC容器对象
ApplicationContext ac =new ClassPathXmlApplicationContext("ApplicationContext.xml");
//根据id值从容器中获取bean实例对象
Person person = (Person) ac.getBean("person");
System.out.println(person);//Person{id=1001, name='郭超'}
//Person person = ac.getBean(Person.class);
//使用此方法获取对象时,要求spring所管理的此类型的对象只能有一个
}
}
IOC容器和Bean的配置
IOC和DI
IOC(Inversion of Control):反转控制
在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率。
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:
反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
传统方式: 我想吃饭 我需要买菜做饭 (需要对象时,要创建赋值然后使用)
反转控制: 我想吃饭 饭来张口 (对象已经准备好,需要的时候直接调用)
那么Spring是如何为我们创建对象的呢?——通过反射newinstance
验证如下:
我们修改Person类,只含有有参构造,省去了无参构造。因为反射通过newinstance创建对象,前提是要有无参构造。
结果报错可以验证出,Spring是通过反射newinstance为我们创建对象的,同时,spring配置文件也会提示我们要在配置文件里面通过有参构造器为属性赋值。
总结:将对象的控制权交给程序本身
DI(Dependency Injection):依赖注入
IOC的另一种表述方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器的资源注入。相对于IOC而言,这种表述更直接。
总结: IOC 就是一种反转控制的思想, 而DI是对IOC的一种具体实现。
<bean id="person" class="com.spring.mod.Person">
<!-- 使用property子元素为bean的属性赋值 -->
<property name="id" value="1001"></property>
<property name="name" value="郭超"></property>
</bean>
如代码所示,bean对象依赖于name和id,为他们赋值就是注入。
IOC容器在Spring中的实现
Spring中有IOC思想, IOC思想必须基于 IOC容器来完成, 而IOC容器在最底层实质上就是一个对象工厂
1)在通过IOC容器读取Bean的实例之前,需要先将IOC容器本身实例化。
2)Spring提供了IOC容器的两种实现方式
① BeanFactory:IOC容器的基本实现,是Spring内部的基础设施,是面向Spring本身的,不是提供给开发人员使用的。
② ApplicationContext:BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。
ApplicationContext的主要实现类
1)ClassPathXmlApplicationContext:对应类路径下的XML格式的配置文件(相对路径)
2)FileSystemXmlApplicationContext:对应文件系统中的XML格式的配置文件(绝对路径)
3)在初始化时就创建单例的bean,也可以通过配置的方式指定创建的Bean是多实例的。
ConfigurableApplicationContext是ApplicationContext的子接口,包含一些扩展方法:refresh()和close()让ApplicationContext具有启动、关闭和刷新上下文的能力。
给bean的属性赋值
通过bean的setXxx()方法赋值
通过bean的构造器赋值
1、Spring自动匹配合适的构造器
<bean id="book" class="com.atguigu.spring.bean.Book" >
<constructor-arg value= "10010"/>
<constructor-arg value= "Book01"/>
<constructor-arg value= "Author01"/>
<constructor-arg value= "20.2"/>
</bean >
2、通过索引值指定参数位置
<bean id="book" class="com.atguigu.spring.bean.Book" >
<constructor-arg value= "10010" index ="0"/>
<constructor-arg value= "Book01" index ="1"/>
<constructor-arg value= "Author01" index ="2"/>
<constructor-arg value= "20.2" index ="3"/>
</bean >
3、通过类型区分重载的构造器
<bean id="book" class="com.atguigu.spring.bean.Book" >
<constructor-arg value= "10010" index ="0" type="java.lang.Integer" />
<constructor-arg value= "Book01" index ="1" type="java.lang.String" />
<constructor-arg value= "Author01" index ="2" type="java.lang.String" />
<constructor-arg value= "20.2" index ="3" type="java.lang.Double" />
</bean >
p名称空间
为了简化XML文件的配置,越来越多的XML文件采用属性而非子元素配置信息。Spring 从2.5版本开始引入了一个新的p命名空间,可以通过<bean>
元素属性的方式配置Bean 的属性。
使用p命名空间后,基于XML的配置方式将进一步简化。
<bean
id="studentSuper"
class="com.atguigu.helloworld.bean.Student"
p:studentId="2002" p:stuName="Jerry2016" p:age="18" />
字面量和ref
1、字面量
1)可以使用字符串表示的值,可以通过value属性或value子节点的方式指定
2)基本数据类型及其封装类、String等类型都可以采取字面值注入的方式
3)若字面值中包含特殊字符,可以使用<![CDATA[]]>把字面值包裹起来
<bean class="com.atguigu.spring.bean.Book" id="bookNull" >
<property name= "bookId" value ="2000"/>
<property name= "bookName">
<null/>
</property>
<property name= "author" value ="nullAuthor"/>
<property name= "price" value ="50"/>
</bean >
2、外部已声明的bean、引用其他的bean(ref)——对引用数据类型赋值
还可以给bean的级联属性赋值
public class Student {
private Integer id;
private String name;
private Integer age;
private String sex;
private Double score;
private Teacher teacher;
public Teacher getTeacher() {
return teacher;
}
... ...
<bean id="s5" class="com.atguigu.spring.di.Student">
<property name="id" value="10055"></property>
<property name="name" value="张三三"></property>
<property name="age" value="23"></property>
<property name="sex" value="男"></property>
<property name="teacher" ref="teacher"></property>
<property name="teacher.tname" value="小红"></property>
</bean>
<bean id="teacher" class="com.atguigu.spring.di.Teacher">
<property name="tid" value="10000"></property>
<property name="tname" value="小明"></property>
</bean>
3、内部bean
当bean实例仅仅给一个特定的属性使用时,可以将其声明为内部bean。内部bean声明直接包含在<property>
或<constructor-arg>
元素里,不需要设置任何id或name属性
内部bean不能使用在任何其他地方
<bean id="s6" class="com.atguigu.spring.di.Student">
<property name="id" value="10066"></property>
<property name="name" value="崔八"></property>
<property name="age" value="18"></property>
<property name="sex" value="男"></property>
<property name="teacher">
<bean id="tt" class="com.atguigu.spring.di.Teacher">
<property name="tid" value="2222"></property>
<property name="tname" value="admin"></property>
</bean>
</property>
</bean>
集合属性赋值
1、数组和List
配置java.util.List类型的属性,需要指定<list>
标签,在标签里包含一些元素。这些标签可以通过<value>
指定简单的常量值,通过<ref>
指定对其他Bean的引用。通过<bean>
指定内置bean定义。通过<null/>
指定空元素。甚至可以内嵌其他集合。 数组的定义和List一样,都使用<list>
元素。 配置java.util.Set需要使用<set>
标签,定义的方法与List一样。
数组:<array> </array>
<bean id="shop" class="com.atguigu.spring.bean.Shop" >
<property name= "categoryList">
<!-- 以字面量为值的List集合 -->
<list>
<value> 历史</value >
<value> 军事</value >
</list>
</property>
<property name= "bookList">
<!-- 以bean的引用为值的List集合 -->
<list>
<ref bean= "book01"/>
<ref bean= "book02"/>
</list>
</property>
</bean >
2、Map
Java.util.Map通过<map>
标签定义,<map>
标签里可以使用多个<entry>
作为子标签。每个条目包含一个键和一个值。
必须在<key>
标签里定义键。
因为键和值的类型没有限制,所以可以*地为它们指定<value>、<ref>、<bean>或<null/>
元素。
可以将Map的键和值作为<entry>
的属性定义:简单常量使用key和value来定义;bean引用通过key-ref和value-ref属性定义。
<bean id="t3" class="com.atguigu.spring.di.Teacher">
<property name="tid" value="10003"></property>
<property name="tname" value="admin"></property>
<property name="bossMap">
<map>
<entry>
<key>
<value>10001</value>
<!-- <ref bean="book02"/>-->
</key>
<value>佟老师</value>
</entry>
<entry>
<key>
<value>10002</value>
</key>
<value>陈老师</value>
</entry>
</map>
</property>
</bean>
3、集合类型的bean
如果只能将集合对象配置在某个bean内部,则这个集合的配置将不能重用。我们需要将集合bean的配置拿到外面,供其他bean引用。 配置集合类型的bean需要引入util名称空间
<bean id="t4" class="com.atguigu.spring.di.Teacher">
<property name="tid" value="10004"></property>
<property name="tname" value="root"></property>
<property name="students" ref="students"></property>
</bean>
<util:list id="students">
<ref bean="s4"/>
<ref bean="s5"/>
<ref bean="s6"/>
</util:list>
<util:map id="map">
<entry>
<key>
<value>1</value>
</key>
<value>张三</value>
</entry>
</util:map>
FactoryBean
Spring中有两种类型的bean,一种是普通bean,另一种是工厂bean,即FactoryBean。
上文介绍的普通bean。
工厂bean跟普通bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂bean的getObject方法所返回的对象。
工厂bean必须实现org.springframework.beans.factory.FactoryBean接口。
示例:
public class Car {
private String brand;
private Double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
..........
}
工厂类:
public class MyFactory implements FactoryBean<Car> {
@Override
public Car getObject() throws Exception {
Car car = new Car();
car.setBrand("奥迪");
car.setPrice(200000.0);
return car;
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Car.class;
}
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
配置文件:
<?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="factory" class="com.atguigu.spring.factorybean.MyFactory"></bean>
</beans>
测试:
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("factory-bean.xml");
Object object = ac.getBean("factory");
System.out.println(object);
}
}
尽管创建的工厂对象,但是返回的是工厂返回的实例对象。
bean的作用域
在Spring中,可以在<bean>
元素的scope属性里设置bean的作用域,以决定这个bean是单实例的还是多实例的。
默认情况下,Spring只为每个在IOC容器里声明的bean创建唯一一个实例,整个IOC容器范围内都能共享该实例:所有后续的getBean()调用和bean引用都将返回这个唯一的bean实例(只能有唯一这一个对象)。该作用域被称为singleton,它是所有bean的默认作用域。
当bean的作用域为单例时,Spring会在IOC容器对象创建时就创建bean的对象实例。(即执行ApplicationContext ac =new ClassPathXmlApplicationContext(“ApplicationContext.xml”);时就创建了对象)
而当bean的作用域为prototype时,IOC容器在获取bean的实例时创建bean的实例对象
bean的生命周期
1、Spring IOC容器对bean的生命周期进行管理的过程:
① 通过构造器或工厂方法创建bean实例
② 为bean的属性设置值和对其他bean的引用
③ 调用bean的初始化方法
④ bean可以使用了
⑤ 当容器关闭时,调用bean的销毁方法
public class Person {
private Integer id;
private String sex;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
System.out.println("Two: 依赖注入");
this.id = id;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
System.out.println("One:创建对象");
}
@Override
public String toString() {
return "Four: Person [id=" + id + ", sex=" + sex + ", name=" + name + "]";
}
public void init() {
System.out.println("Three: 初始化");
}
public void destory () {
System.out.println("Five: 销毁");
}
}
在配置bean时,通过init-method和destroy-method 属性为bean指定初始化和销毁方法
<bean id="personone" class="com.spring.mod.Person" scope="prototype" init-method="init" destroy-method="destroy">
<!-- 使用property子元素为bean的属性赋值 -->
<property name="id" value="1001"></property>
</bean>
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("life.xml");
Person person = ac.getBean("person", Person.class);
System.out.println(person);
ac.close();
}
}
执行结果:从One到Five
注:如果bean:scope=“prototype”,则:ac.close();不会执行destroy这一步。
2、bean的后置处理器
① bean后置处理器允许在调用初始化方法前后对bean进行额外的处理
② bean后置处理器对IOC容器里的所有bean实例逐一处理,而非单一实例。
其典型应用是:检查bean属性的正确性或根据特定的标准更改bean的属性。
③ bean后置处理器需要实现接口:
org.springframework.beans.factory.config.BeanPostProcessor。在初始化方法被调用前后,Spring将把每个bean实例分别传递给上述接口的以下两个方法:
●postProcessBeforeInitialization(Object, String)
●postProcessAfterInitialization(Object, String)
public class AfterHandler implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Person person = (Person) bean;
if(person.getSex().equals("男")) {
person.setName("张无忌");
}else {
person.setName("赵敏");
}
return person;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
return bean;//避免BeforeInitialization操作失败,直接将bean返回
}
}
<bean id="person" class="com.atguigu.ioc.life.Person" init-method="init" destroy-method="destory">
<property name="id" value="1001"></property>
<property name="sex" value="男"></property>
</bean>
<bean class="com.atguigu.ioc.life.AfterHandler"></bean>
添加bean后置处理器后bean的生命周期:
①通过构造器或工厂方法创建bean实例
②为bean的属性设置值和对其他bean的引用
③将bean实例传递给bean后置处理器的postProcessBeforeInitialization()方法
④调用bean的初始化方法
⑤将bean实例传递给bean后置处理器的postProcessAfterInitialization()方法
⑥bean可以使用了
⑦当容器关闭时调用bean的销毁方法
引入外部资源文件
当bean的配置信息逐渐增多时,查找和修改一些bean的配置信息就变得愈加困难。这时可以将一部分信息提取到bean配置文件的外部,以properties格式的属性文件保存起来,同时在bean的配置文件中引用properties属性文件中的内容,从而实现一部分属性值在发生变化时仅修改properties属性文件即可。这种技术多用于连接数据库的基本信息的配置。
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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-3.0.xsd
">
<!--一、直接配置-->
<!-- <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">-->
<!-- <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/test"></property>-->
<!-- <property name="username" value="root"></property>-->
<!-- <property name="password" value="123456"></property>-->
<!-- </bean>-->
<!--二、使用外部的属性文件 -->
<!-- 加载资源文件方法① -->
<!-- <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">-->
<!-- <property name="location" value="db.properties"></property>-->
<!-- </bean>-->
<!--加载资源文件方法②:注意要引入context命名空间-->
<!-- classpath:xxx 表示属性文件位于类路径下 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 通过加载的资源文件配置信息 -->
<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>
</beans>
测试:
@Test
public void testdb() throws SQLException {
ApplicationContext ac=new ClassPathXmlApplicationContext("datasource.xml");
DruidDataSource bean = ac.getBean("datasource", DruidDataSource.class);
System.out.println(bean.getConnection());//com.mysql.jdbc.JDBC4Connection@3c0a50da
}
自动装配
自动装配的概念
1)手动装配:以value或ref的方式明确指定属性值都是手动装配。
2)自动装配: 根据指定的装配规则,不需要明确指定,Spring自动将匹配的属性值注入bean中。(一定是引用数据类型)
装配模式
1)根据类型自动装配:将类型匹配的bean作为属性注入到另一个bean中。若IOC容器中有多个与目标bean类型一致的bean,Spring将无法判定哪个bean最合适该属性,所以不能执行自动装配(bytype)
2)根据名称自动装配:必须将目标bean的名称和属性名设置的完全相同(byname)
<!--
autowire:根据某种策略自动为非字面量属性赋值
autowire="byName|byType"
byName:通过属性名和spring容器中bean的id进行比较,若一致则可直接赋值
byType:通过spring容器中bean的类型,为兼容性的属性赋值
在使用byType的过程中,要求spring容器中只能有一个能为属性赋值的bean
选用建议: 当设置autowire属性,会作用于该bean中所有的非字面量属性,因此谁都不用
-->
<bean id="emp" class="com.atguigu.ioc.auto.Emp" autowire="byType">
<property name="eid" value="1001"></property>
<property name="ename" value="张三"></property>
</bean>
<bean id="car1" class="com.atguigu.ioc.auto.Car">
<property name="cid" value="666666"></property>
<property name="cname" value="霸道"></property>
</bean>
<bean id="car2" class="com.atguigu.ioc.auto.Car">
<property name="cid" value="8888888"></property>
<property name="cname" value="奥迪A8"></property>
</bean>
<bean id="dept1" class="com.atguigu.ioc.auto.Dept">
<property name="did" value="11111"></property>
<property name="dname" value="开发部"></property>
</bean>
通过注解配置bean
概述
相对于XML方式而言,通过注解的方式配置bean更加简洁和优雅,而且和MVC组件化开发的理念十分契合,是开发中常用的使用方式。
必须在原有JAR包组合的基础上再导入一个:spring-aop-4.0.0.RELEASE.jar
使用注解标识组件(bean)
1)普通组件:@Component
标识一个受Spring IOC容器管理的组件
2)持久化层组件:@Repository
标识一个受Spring IOC容器管理的持久化层组件
3)业务逻辑层组件:@Service
标识一个受Spring IOC容器管理的业务逻辑层组件
4)表述层控制器组件:@Controller
标识一个受Spring IOC容器管理的表述层控制器组件
注意:事实上Spring并没有能力识别一个组件到底是不是它所标记的类型,即使将 @Respository注解用在一个表述层控制器组件上面也不会产生任何错误,所以 @Respository、@Service、@Controller这几个注解仅仅是为了让开发人员自己明确当前的组件扮演的角色。(功能都一样,也都可以和@Component互换)
package com.spring.usermodel.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
public UserController(){
System.out.println("UserController");
}
}
package com.spring.usermodel.service;
import org.springframework.stereotype.Service;
@Service
public class UerServiceImpl implements UserService {
public UerServiceImpl(){
System.out.println("UserServiceImpl");
}
}
package com.spring.usermodel.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
public UserDaoImpl(){
System.out.println("UserDaoImpl");
}
}
扫描组件
组件被上述注解标识后还需要通过Spring进行扫描才能够侦测到。
1)指定被扫描的package
<context:component-scan base-package="com.spring.usermodel"></context:component-scan>
2)详细说明
①base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包及其子包中的所有类。
②当需要扫描多个包时可以使用逗号分隔。
如果仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern属性过滤特定的类,示例:
<context:component-scan
base-package="com.atguigu.component"
resource-pattern="autowire/*.class"/>
④包含与排除<context:include-filter>
子节点表示要包含的目标类
注意:通常需要与use-default-filters属性配合使用才能够达到“仅包含某些组件”这样的效果。即:通过将use-default-filters属性设置为false,禁用默认过滤器,然后扫描的就只是include-filter中的规则指定的组件了。
<context:exclude-filter>
子节点表示要排除在外的目标类
过滤表达式:
annotation:过滤所有标注了XxxAnnotation的类。这个规则根据目标组件是否标注了指定类型的注解进行过滤。eg:org.springframework.stereotype.Controller
assignable:过滤所有BaseXxx类的子类。这个规则根据目标组件是否是指定类型的子类的方式进行过滤。eg:com.spring.usermodel.service.UserServiceImpl
演示代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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">
<!--
<context:component-scan>:扫描组件,对设置的包下面的类进行扫苗,会将加上注解的类作为spring的组件进行加载
组件:指spring中管理的bean
作为spring的组件进行加载:会自动在spring的配置文件中生成相对应的bean,这些bean的id会以类的首字母小写为值
例如: <bean id="userController" class="com.spring.usermodel.controller.UserController">
<context:include-filter>:在设定的包结构下,再次通过注解或类型具体包含到某个或某几个类
注意:在使用包含时,一定要设置use-default-filters="false",将默认的过滤(即扫描包下所有的类)关闭
<context:exclude-filter>:在设定的包结构下,再次通过注解或类型排除某个或某几个类
注意:在使用排除时,一定要设置use-default-filters="true",将默认的过滤(即扫描包下所有的类)打开
切记:一个<context:component-scan>中可以出现多个include,也可以同时出现多个exclude,但是两个不能同时出现
-->
<context:component-scan base-package="com.spring.usermodel" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="assignable" expression="com.spring.usermodel.service.UserServiceImpl"/>
</context:component-scan>
</beans>
public class test {
public static void main(String[] args) {
ApplicationContext ac =new ClassPathXmlApplicationContext("user.xml");
//验证通过注解扫描,自动创建了相关对象
UserController userController = ac.getBean("userController", UserController.class);
System.out.println(userController);//com.spring.usermodel.controller.UserController@26a7b76d
UserServiceImpl userServiceImpl = ac.getBean("userServiceImpl", UserServiceImpl.class);
System.out.println(userServiceImpl);//com.spring.usermodel.service.UserServiceImpl@7a9273a8
UserDaoImpl userDaoImpl = ac.getBean("userDaoImpl", UserDaoImpl.class);
System.out.println(userDaoImpl);//报错
}
}
基于注解的自动装配:
1)需求
Controller组件中往往需要用到Service组件的实例,Service组件中往往需要用到 Repository组件的实例。Spring可以通过注解的方式帮我们实现属性的装配。
2)实现依据
在指定要扫描的包时,<context:component-scan>
元素会自动注册一个bean的后置处 理器:AutowiredAnnotationBeanPostProcessor的实例。该后置处理器可以自动装配标记了@Autowired、@Resource或@Inject注解的属性。
UserController :
package com.spring.usermodel.controller;
import com.spring.usermodel.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller(value = "controllernickname")
//@Controller("controllernickname")
public class UserController {
@Autowired
private UserService userService;
public void addUser(){
userService.addUser();
}
public UserController(){
System.out.println("UserController");
}
}
UserServiceImpl :
package com.spring.usermodel.service;
import com.spring.usermodel.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier(value = "userDaoMybatisImpl")
private UserDao userDao;
public UserServiceImpl(){
System.out.println("UserServiceImpl");
}
@Override
public void addUser() {
userDao.addUser();
}
}
UserDaoMybatisImpl
package com.spring.usermodel.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoMybatisImpl implements UserDao {
@Override
public void addUser() {
System.out.println("UserDaoMybatisImpl添加成功");
}
}
UserDaoImpl
package com.spring.usermodel.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
public UserDaoImpl(){
System.out.println("UserDaoImpl");
}
@Override
public void addUser() {
System.out.println("UserDaoImpl添加成功");
}
}
public class test {
public static void main(String[] args) {
ApplicationContext ac =new ClassPathXmlApplicationContext("user.xml");
UserController userController = ac.getBean("controllernickname",UserController.class);
userController.addUser();
}
}
<context:component-scan base-package="com.spring.usermodel" use-default-filters="true">
</context:component-scan>
总结:
基于注解的组件化管理:
@Component,@Controller(控制层),@Service(业务层),@Repository(持久层)
以上四个注解功能完全相同,不过在实际开发中,要在实现不同功能的类上加上相应的注解
完成组件化管理的过程:
1、在需要被spring管理的类上加上相应注解
2、在配置文件中通过<context:component-scan>
对所设置的包结构进行扫描,就会将加上注解的类,作为spring的组件进行加载组件:指spring中管理的bean作为spring的组件进行加载:会自动在spring的配置文件中生成相对应的bean,这些bean的id会以类的首字母小写为值;也可以通过@Controller(“beanId”)为自动生成的bean指定id
自动装配:
1、 在需要赋值的非字面量属性上,加上@Autowired,就可以在spring容器中,通过不同的方式匹配到相对应的bean;@Autowired装配时,会默认使用byType的方式,此时要求spring容器中只有一个能够为其赋值; 当byType实现不了装配时,会自动切换到byName,此时要求spring容器中,有一个bean的id和属性名一致
2、若自动装配时,匹配到多个能够复制的bean,可使用@Qualifier(value=“beanId”)指定使用的bean
3、 @Autowired和@Qualifier(value=“beanId”)可以一起作用域一个带形参的方法上,此时,@Qualifier(value=“beanId”)所指定的bean作用于形参