spring框架-1-Bean
spring框架介绍
spring是什么
Spring是一个 IOC(DI) 和 AOP 容器框架
spring分为哪些模块,整体架构
spring怎样导入到项目
1. maven方式
spring的核心依赖(core beans expression context)
<!-- spring 5.2.0 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
2. 下载jar包,在导入项目
自己在网上下载jar包引入项目了,我不在此提供jar包的下载地址
通过xml文件配置bean
1. 声明一个简单的bean
在Spring配置文件中写一个bean标签就可以了
<bean id="stu" class="online.abor.domain.Student"/>
class:指定这个bean是什么类型的bean,就是简单来说就是类的路径
id:就像是数据库中一个表的主键一样,在这里是bean的唯一标识
2. 配置bean的属性
-
配置bean的基本值
需要用到bean的子标签property来配置<bean id="car" class="online.abor.domain.Car"> <property name="brand" value="BMW"/> <property name="maxSpeed" value="240"/> <property name="price" value="540000"/> </bean>
-
配置引用类型的值
-
需要用property的属性ref来使其指向其他的bean
<bean id="stuCar" class="online.abor.domain.Student"> <property name="name" value="carStu"/> <property name="car" ref="car"/> </bean>
-
使用内部bean来配置
这个内部bean是不需要id字段的,因为其他的bean根本就访问不到这个内部bean<bean id="stuInnerCar" class="online.abor.domain.Student"> <property name="name" value="stuInnerCar"/> <property name="car"> <bean class="online.abor.domain.Car"> <property name="brand" value="BenChi"/> <property name="maxSpeed" value="280"/> <property name="price" value="340000"/> </bean> </property> </bean>
-
级联属性
通过 . 的方式设置引用类型的值<bean id="cascadeStu" class="online.abor.domain.Student"> <property name="name" value="cascadeStu"/> <property name="car" ref="car"/> <property name="car.brand" value="SanYi"/> </bean>
==注意:==如果不先实例化一个car的直接使用级联属性是会报NullValueInNestedPathException异常的,原因是bean在初始化时,并不会为引用类型的字段自动实例化
- 配置List类的列表
通过property 的子标签list配置需要的列表
list下可以直接写bean,也可以使用引用标签ref引用其他的bean<bean id="carsStu" class="online.abor.domain.Student"> <property name="name" value="carsStu"/> <property name="cars"> <list> <ref bean="car"/> <bean class="online.abor.domain.Car"> <property name="brand" value="BenChi"/> <property name="maxSpeed" value="280"/> <property name="price" value="340000"/> </bean> </list> </property> </bean>
- 配置Map值
通过property 下的map子标签实现
map中的每一个键值对对应一个entry子标签<bean id="mapStu" class="online.abor.domain.Student"> <property name="name" value="mapStu"/> <property name="parents"> <map> <entry key="Father" value="50"/> <entry key="Mother" value="48"/> </map> </property> </bean>
- 配置Properties引用类型值
通过property 的子标签props设置,每一个prop子标签都是一个属性<bean id="propStu" class="online.abor.domain.Student"> <property name="name" value="propStu"/> <property name="dataSource"> <props> <prop key="username">root</prop> <prop key="password">123456</prop> <prop key="url">jdbc:mysql://localhost:3306:mysql</prop> <prop key="driver">com.mysql.cj.jdbc.Driver</prop> </props> </property> </bean>
- 通过p标签简化配置bean的属性
不需要再写property 标签,直接用 p:属性名 给属性赋值<bean id="pStu" class="online.abor.domain.Student" p:name="pStu" p:cars-ref="carList"/>
- 将列表抽离出来供所有bean公共使用
列表不需要写class属性,但必须写id属性,否则其他bean不知道如何引用此列表<util:list id="carList"> <ref bean="car"/> <bean class="online.abor.domain.Car"> <constructor-arg value="LingMu"/> <constructor-arg value="180000.23"/> <constructor-arg value="100"/> </bean> </util:list>
通过外部属性文件配置bean
一般对于一些项目的配置文件,写在bean配置文件里是很不方便后期更改的,所以一般我们会写在外部属性文件里面,如jdbc.properties文件记录数据库连接的一些信息
- 需要先将外部文件导入进来
在spring配置文件中引入<context:property-placeholder location="jdbc.properties"/>
- 在使用 ${ 属性名 } 引用外部文件中的属性来配置bean
需要先将配置文件引入进来
在使用 ${ 属性名 } 引用属性<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="alibabaDSP" class="com.alibaba.druid.pool.DruidDataSource"> <property name="username" value="${user}"/> <property name="password" value="${password}"/> <property name="url" value="${url}"/> <property name="driverClassName" value="${driverClass}"/> </bean>
spEL表达式
字面量
<bean id="stu01" class="online.abor.domain.Student">
<!-- 使用单引号或者双引号界定字符串 -->
<property name="name" value="#{'spELName'}"/>
<!-- 整数的字面量 -->
<property name="age" value="#{18}"/>
<property name="car">
<bean class="online.abor.domain.Car">
<!-- 小数的字面量 -->
<property name="price" value="#{240000.85}"/>
</bean>
</property>
<!-- 布尔值 -->
<property name="status" value="#{true }"/>
</bean>
引用Bean、属性和方法
<bean id="stu02" class="online.abor.domain.Student">
<property name="name" value="othersStu"/>
<!-- 引用其他bean的字段 -->
<property name="status" value="#{stu01.status}"/>
<property name="car" value="#{stu01.car}"/>
<!-- 调用其他类的方法 -->
<property name="relatives">
<map>
<entry key="str" value="#{stu01.toString()}"/>
<!-- 方法级联链式操作 -->
<entry key="str2" value="#{stu01.toString().toUpperCase()}"/>
</map>
</property>
</bean>
运算符号
<!-- 运算符号 -->
<bean id="stu03" class="online.abor.domain.Student">
<property name="name" value="operatorStu"/>
<!-- 逻辑运算符号支持 and or ! not -->
<property name="status" value="#{stu01.status and true or false and !false}"/>
<!-- if else -->
<property name="age" value="#{stu01.status==true?18:20}"/>
<!-- 正则表达式 -->
<property name="sex" value="#{'operatorStu' matches '[0-9]'?'男':'女'}"/>
</bean>
引用静态类的属性或方法
<bean id="stu04" class="online.abor.domain.Student">
<property name="age" value="#{T(Integer).MAX_VALUE}"/>
</bean>
bean之间的关系
继承
bean 使用parent属性指定需要继承的父bean
<bean id="autoWireStu" class="online.abor.domain.Student">
<property name="name" value="autoWireStu"/>
<property name="sex" value="男"/>
</bean>
<!-- 继承 -->
<bean id="extendsStu" class="online.abor.domain.Student" parent="autoWireStu">
<property name="name" value="extendsStu"/>
</bean>
继承可以继承父bean的属性
依赖
bean使用depends-on属性指定需要依赖的bean
如果IOC容器中不存在此bean,会报异常NoSuchBeanDefinitionException
<!-- 依赖 IOC容器内必须有这个实例,才可以通过IOC的初始化-->
<bean id="dependCar" class="online.abor.domain.Car" parent="car"/>
<bean id="dependStu" class="online.abor.domain.Student" depends-on="dependCar">
<property name="name" value="dependStu"/>
</bean>
抽象bean
bean使用abstract属性来指定,不可以被实例化
如果这个bean被错误的实例化引用,会报BeanIsAbstractException异常
<!-- 抽象bean 不可实例化-->
<bean id="abstractStu" class="online.abor.domain.Student"
p:name="abName" p:age="18" p:sex="男" abstract="true"/>
<bean id="exAbsStu" parent="abstractStu" class="online.abor.domain.Student">
<property name="name" value="exAbsStu"/>
</bean>
bean的生命周期
init与destroy方法
指定bean的init-method和destroy-method属性
-
先在Student类中定义init和destroy方法,方法名是任意的
public void init(){ System.out.println("Student's init-method()"); } public void destroy(){ System.out.println("Student's destroy-method()"); }
-
在配置文件中注入属性
<bean id="stu01" class="online.abor.domain.Student" init-method="init" destroy-method="destroy" p:name="initDestroyStu"/>
bean的后置处理器PostProcessor
-
自定义一个类实现BeanPostProcessor接口,重写postProcessBeforeInitialization与postProcessAfterInitialization方法
public class MyPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization..."); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization..."); return bean; } }
-
在配置文件中注入自定义的PostProcessor就可以了就可以了
不需要赋id属性,只需要class属性,IOC容器会自动识别为后置处理器<bean class="online.abor.others.MyPostProcessor"/>
bean的生命周期的执行顺序
- 构造器
- setter
- postProcessBeforeInitialization
- 初始化方法 init-method
- postProcessAfterInitialization
- 销毁方法 destroy-method
通过工厂方法配置bean
静态工厂方法
<bean id="dateFormat" class="java.text.DateFormat" factory-method="getDateInstance">
<!-- 可以通过 constructor-arg 子节点为静态工厂方法指定参数 -->
<constructor-arg value="2"></constructor-arg>
</bean>
实例工厂方法
<!-- 实例工厂方法 -->
<!-- 先创建工厂对象 -->
<bean id="simpleDateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd hh:mm:ss"/>
</bean>
<!-- 在调用非静态方法返回实例 -->
<bean id="dateTime" factory-bean="simpleDateFormat" factory-method="parse">
<constructor-arg value="2019-12-1 12:18:20"/>
</bean>
自定义实例工厂方法返回自定义类型bean
-
自定义一个类实现FactoryBean< T >接口,并重写其getObject和getObjectType方法
public class MyStudentBeanFactory implements FactoryBean<Student> { @Override public Student getObject() throws Exception { Student student = new Student(); student.setName("myStudentBeanFactoryStu"); return student; } @Override public Class<?> getObjectType() { return Student.class; } }
-
配置文件中注入factorybean
<bean id="studentBean" class="online.abor.others.MyStudentBeanFactory"/>
通过注解配置bean
-
在配置文件中通过context:component-scan指定需要扫描的包
<context:component-scan base-package="online.abor.annotation"/>
-
在类上添加注解(@Component、@Controller 、@Service、@Repository)
注解可以添加value参数指定生成bean的id@Service("userService") public class UserServiceImpl implements UserService { private final UserDao userDao; public UserServiceImpl(UserDao userDao) { this.userDao = userDao; } @Override public void save() { System.out.println("UserServiceImpl's save()"); userDao.save(); } }
不添加value参数的话,IOC容器用的是默认的命名规则,首字母小写,其后的保持与原类名一致