Spring配置
别名
<!--为已关联的bean取别名,之前的名字不会被覆盖,等于多了一个名字-->
<alias name="test" alias="mytest"/>
Bean的配置
<!--
id : bean的唯一标识符
class : bean对象对应的全限定名,包名+类名
name : 别名,且比alias更高级,可以取多个,分隔符多种多样
-->
<bean id="test" class="testClass" name="t1,t2 t3;t4">
</bean>
import
一般用于团队开发,将不同成员负责的不同配置导入到同一个配置中,之后使用这个配置便可以使用所有导入的配置
![](https://img.haomeiwen.com/i22864240/2455ca6c9e249361.png)
![](https://img.haomeiwen.com/i22864240/ac07b354de3ad493.png)
之后使用applicationContext即可使用beans、beans2、beans3所配置的bean
注意:若内部配置的bean名称相同且内容相同,spring会自动覆盖成一个
复杂注入实验环境搭建
1、创建复杂实体类
public class student {
//普通值
private String isStr;
//类参数
private address isAddr;
//数组
private String[] isStrs;
//list集合
private List<String> isList;
//map集合
private Map<String,String> isMap;
//set集合
private Set<String> isSet;
//properties配置文件
private Properties isProperties;
//null空指针
private String isNull;
@Override
public String toString() {
return "isStr='" + isStr + '\'' +
"\nisAddr=" + isAddr.getCity() +
"\nisStrs=" + Arrays.toString(isStrs) +
"\nisList=" + isList +
"\nisMap=" + isMap +
"\nisSet=" + isSet +
"\nisProperties=" + isProperties +
"\nisNull='" + isNull + '\'';
}
public String getIsStr() {
return isStr;
}
public void setIsStr(String isStr) {
this.isStr = isStr;
}
public address getIsAddr() {
return isAddr;
}
public void setIsAddr(address isAddr) {
this.isAddr = isAddr;
}
public String[] getIsStrs() {
return isStrs;
}
public void setIsStrs(String[] isStrs) {
this.isStrs = isStrs;
}
public List<String> getIsList() {
return isList;
}
public void setIsList(List<String> isList) {
this.isList = isList;
}
public Map<String, String> getIsMap() {
return isMap;
}
public void setIsMap(Map<String, String> isMap) {
this.isMap = isMap;
}
public Set<String> getIsSet() {
return isSet;
}
public void setIsSet(Set<String> isSet) {
this.isSet = isSet;
}
public Properties getIsProperties() {
return isProperties;
}
public void setIsProperties(Properties isProperties) {
this.isProperties = isProperties;
}
public String getIsNull() {
return isNull;
}
public void setIsNull(String isNull) {
this.isNull = isNull;
}
}
2、创建配置文件
<?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">
</beans>
依赖注入
1、构造器注入
参考spring入门(https://www.jianshu.com/p/133db8383263)的构造器注入
2、set注入(重点)
- 依赖注入
- 依赖:bean对象的创建依赖容器
- 注入:bean对象中的所有属性,由容器注入
实现:
<?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-->
<bean id="addr" class="address">
<property name="city" value="杭州"/>
</bean>
<!--创建bean-->
<bean id="stu" class="student">
<!--注入普通值-->
<property name="isStr" value="杨子贤"/>
<!--注入bean-->
<property name="isAddr" ref="addr"/>
<!--注入数组-->
<property name="isStrs">
<array>
<value>《红楼梦》</value>
<value>《西游记》</value>
<value>《三国演义》</value>
<value>《水浒传》</value>
</array>
</property>
<!--注入list集合-->
<property name="isList">
<list>
<value>1111</value>
<value>2222</value>
<value>3333</value>
</list>
</property>
<!--注入map集合-->
<property name="isMap">
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
<entry key="key3" value="value3"/>
</map>
</property>
<!--注入set集合-->
<property name="isSet">
<set>
<value>4444</value>
<value>5555</value>
<value>6666</value>
</set>
</property>
<!--注入properties配置文件-->
<property name="isProperties">
<props>
<prop key="driver">cn.jdbc.cj.xxx</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
<!--注入null空指针-->
<!--设置空字符串-->
<!--<property name="isNull" value=""/>-->
<!--设置null值-->
<property name="isNull">
<null/>
</property>
</bean>
</beans>
![](https://img.haomeiwen.com/i22864240/8697413119a97aa8.png)
补充:
1、如上导入list、map等复杂数据时,每次都手动是很麻烦的,尤其是有很多重复集合的时候,此时可以使用util来简化,导入util命名空间
![](https://img.haomeiwen.com/i22864240/8f21995d6a814e2e.png)
<util:list id="list"> <!--等于为list创建了一个bean,使用容器对象get也可以获取-->
<value>1111</value>
<value>2222</value>
<value>3333</value>
</util:list>
<!--注入list集合-->
<property name="isList" ref="list"> <!--此时使用ref引入即可-->
<!-- <list>-->
<!-- <value>1111</value>-->
<!-- <value>2222</value>-->
<!-- <value>3333</value>-->
<!-- </list>-->
</property>
2、可以使用级联赋值的方式,直接修改已经引入的对象属性的属性,注意:一修改,引用的对象本身的该属性也会被修改
![](https://img.haomeiwen.com/i22864240/d581150e3d7b20a4.png)
3、可以使用parent指定继承已注册的同类型的bean信息,此时再对属性进行赋值,会覆盖父类信息
![](https://img.haomeiwen.com/i22864240/41af184123e7b1ec.png)
4、使用abstract将一个已注册的bean设为抽象bean,使得该bean只能被继承,无法被调用
![](https://img.haomeiwen.com/i22864240/d6972143370146d2.png)
若调用被abstract修饰的bean会报错
![](https://img.haomeiwen.com/i22864240/bdef8f1874d92c1e.png)
5、使用depends-on可以决定bean创建的顺序,了解即可
6、使用工厂模式创建bean
- 静态工厂:直接使用工厂.工厂方法()创建
public class staticFactory {
public static airPlane getAirPlane(String id) {
System.out.println("静态工厂正在制造飞机.....");
airPlane air = new airPlane();
air.setName("兴邦航空");
air.setId(id);
air.setCaptionName("张机长");
air.setEditName("李维修长");
return air;
}
}
- 动态工厂:需要先实例化工厂本身
public class dynamicFactory {
public airPlane getAirPlane(String id) {
System.out.println("动态工厂正在制造飞机.....");
airPlane air = new airPlane();
air.setName("兴邦航空");
air.setId(id);
air.setCaptionName("张机长");
air.setEditName("李维修长");
return air;
}
}
- Factorybean实现类:spring本身的factory接口
import org.springframework.beans.factory.FactoryBean;
import pojo.airPlane;
public class myFactoryBean implements FactoryBean<airPlane> {
public airPlane getObject() throws Exception { //获取对象的方法
System.out.println("Spring工厂正在制造飞机.....");
airPlane air = new airPlane();
air.setName("兴邦航空");
air.setId("1003");
air.setCaptionName("张机长");
air.setEditName("李维修长");
return air;
}
public Class<?> getObjectType() { //获取对象的类型
return airPlane.class;
}
public boolean isSingleton() { //获取对象的方式是否为单例,false表示为单例,true表示不为单例
return false;
}
}
使用工厂创建bean:
1、静态
无需实例化工厂本身,调用方法创建对象
![](https://img.haomeiwen.com/i22864240/3d15a9bc8fcbcfeb.png)
![](https://img.haomeiwen.com/i22864240/acd1a0418ea806dc.png)
可见调用工厂创建对应实体类成功
2、动态
![](https://img.haomeiwen.com/i22864240/a0f31eb688ccae0e.png)
![](https://img.haomeiwen.com/i22864240/431d99e7a98963ed.png)
3、Factorybean实现类,这样方式的好处是,天生的有懒加载的效果,只在调用时才会实例化对象,且有更高级的功能
![](https://img.haomeiwen.com/i22864240/f35f5ccb5928339e.png)
![](https://img.haomeiwen.com/i22864240/51b1f35530cc059a.png)
7、创建bean的生命周期方法
使用init-method指定初始化方法,使用destory-method指定销毁方法
8、使用spring管理数据库连接池,可见,spring默认的单例模式是非常适合web开发中使用的连接池的
首先导入依赖
![](https://img.haomeiwen.com/i22864240/42e78fd4bd522223.png)
在xml中注册连接池工厂bean静态工厂
![](https://img.haomeiwen.com/i22864240/e9196e2ffbf574c3.png)
测试连接
![](https://img.haomeiwen.com/i22864240/67b7a460aaf942ca.png)
9、动态获取外部配置文件
![](https://img.haomeiwen.com/i22864240/d1fb2a2a7efe9abc.png)
![](https://img.haomeiwen.com/i22864240/a71c1ade0665ce59.png)
![](https://img.haomeiwen.com/i22864240/b0ecedc4b77a7e18.png)
3、拓展方式注入
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
分别简化了set注入(p)和构造器注入(c)
<bean id="stu2" class="student"
p:isStr="yzx_p"
p:isAddr-ref="addr2"
p:isStrs="1,2,3,4,5"
p:isList="6,7,8,9,10"
p:isSet="11,12,13,14,15">
<!--注入普通值-->
<!--注入bean-->
<!--注入数组-->
<!--注入list集合-->
<!--注入map集合-->
<!--注入set集合-->
<!--注入properties配置文件-->
<!--注入null空指针-->
<!--设置空字符串-->
<!--设置null值-->
</bean>
<!-- <bean id="stu3" class="student"-->
<!-- c:isStr="yzx_c">-->
<!-- </bean>-->
bean的作用域
![](https://img.haomeiwen.com/i22864240/bfa2ad9bb8dff01e.png)
测试代码:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
student stu = context.getBean("stu", student.class);
student stu2 = context.getBean("stu", student.class);
System.out.println(stu == stu2);
singleton(spring默认机制):
<bean id="stu" class="student" scope="singleton">
运行结果:
![](https://img.haomeiwen.com/i22864240/42f869abe8b51b08.png)
prototype:
<bean id="stu" class="student" scope="prototype">
运行结果:
![](https://img.haomeiwen.com/i22864240/d25333e5dbb3739a.png)
其余的只在web开发中使用,效果也与web中定义的一致
bean的自动装配
1、根据名称自动装配
缺点:名称不同则无法自动装配,多了之后容易乱
<bean id="cat" class="Cat"/>
<bean id="dog" class="Dog"/>
<bean id="master" class="Master" autowire="byName">
<property name="name" value="张三"/>
</bean>
自动根据set方法后半段的名称将首字母小写后寻找同名bean,例如setDog,会自动寻找名为dog的bean进行装配
2、根据类型自动装配
缺点:类型不唯一时,无法自动装配,对用类型必须在bean中唯一
<bean class="Cat"/>
<bean class="Dog"/>
<bean id="master" class="Master" autowire="byType">
<property name="name" value="张三"/>
</bean>
自动根据set方法需要的参数类型装配bean,无关名称,缺点是若有两个同类型set则无法自动装配,会报错,例如有两个dog类型的,则无法使用此方法自动装配
3、根据构造器自动装配
![](https://img.haomeiwen.com/i22864240/b51e7a2b13274c6b.png)
4、自动装配集合
![](https://img.haomeiwen.com/i22864240/67c46f8806b5feb1.png)
![](https://img.haomeiwen.com/i22864240/04a341df398fd7bd.png)
使用注解自动装配
![](https://img.haomeiwen.com/i22864240/01c85fc4694feb7f.png)
之后在实体类中指定属性或方法上使用@AutoWired注解即可,注意:只能对自定义类的属性使用,基本属性无效
![](https://img.haomeiwen.com/i22864240/fa9ec26b41cec7e4.png)
![](https://img.haomeiwen.com/i22864240/b7e332f4dc142a05.png)
装配规则:
- 首先根据类型(继承关系也算做同一类)去寻找已注册的bean,若找到一个同类型的bean,则自动注入,若一个都没找到,则抛出异常
- 若找到多个同类型的bean,则以变量名为id和找到的bean的id做匹配,若有id相同的则自动注入
- 若未找到匹配的id,会抛出异常,也可以使用@Qualifier来指定匹配的id名
使用@Qualifier("cat11")可以装配指定名称的bean,等于使用byname方式装配
![](https://img.haomeiwen.com/i22864240/dd404585a3db84af.png)
若仍然找不到,则抛出异常,可见,使用@Autowired装配必须找到对应的bena,否则就会报错,此时,可以设置required属性,达到限制该属性是否可以为null的效果,false允许为null,true则不允许为null,同时使用@Nullable注解,也可以达到允许该属性为null的效果
![](https://img.haomeiwen.com/i22864240/b384d3e0e8e3d7d0.png)
使用非spring的注解@Resource也可以达到自动装配的效果
![](https://img.haomeiwen.com/i22864240/2764ce325db7ec42.png)
使用此注解,不指定name时,使用bytype,指定name时,使用byname,一个注解可达到两个注解的效果,且扩展性更强,因为这是J2EE定义的标准,但是因为抛开已经淘汰的EJB容器,只有spring一家容器框架,所以这个优点也不算优点了,了解即可
SpEL表达式
与EL表达式类似,但是spring的EL表达式更强大,可以调用静态方法和非静态方法
![](https://img.haomeiwen.com/i22864240/56eefb4f45e2e3ec.png)
泛型依赖注入
-
创建实体类
目录结构
public abstract class basicDao<T> {
public abstract void showInfo();
}
//bookDao和userDao分别使用注解注册,并集成basicDao
@Repository
public class userDao extends basicDao<user>{
public void showInfo() {
System.out.println("user.................");
}
}
@Repository
public class bookDao extends basicDao<book>{
public void showInfo() {
System.out.println("book............");
}
}
public class basicService<T> {
@Autowired
private basicDao<T> dao;
public void showInfo() {
dao.showInfo();
}
}
//userService和bookSerive无任何实现,继承basicService即可
@Service
public class userService extends basicService<user>{
}
@Service
public class bookService extends basicService<book>{
}
此时basicService中自动注入的basicDao<T> dao无效,因为本身没有被注册到容器中,但是继承了他的两个子类,虽然无法调用basicDao<T> dao本身,但是可以获取showInfo方法,而他们也是有basicDao<T> dao这个属性的,只是不能使用而已,此时他们被注册了,则spring会自动注入已注册的userDao和bookDao的bean,而泛型被spring很只能的注入了
原理:
首先观察
![](https://img.haomeiwen.com/i22864240/fd3884e1666a2f4e.png)
两个basicService的子类,在继承basicService时,都设置了各自的泛型为确定的一个对象,此时他们内部虽然没有东西,但是因为继承了basicService,所以他们其实是拥有了basicService的所有东西的,只是有些能用,有些不能用
![](https://img.haomeiwen.com/i22864240/b1c89f511cf90dd7.png)
此时虽然basicService没有被注册到容器中,但是两个子类已经注册了,自动装配就会生效,而且会按照传入的泛型进行自动装配,即
![](https://img.haomeiwen.com/i22864240/7bc906a8a6482f47.png)
而userDao和bookDao继承了父类,也就有了父类的类型,他们已经注册到了容器中,所以自动装配时,会找到他们
![](https://img.haomeiwen.com/i22864240/99bb81e788881859.png)
刚好一一匹配,所以正常注入到了对应的属性中,由此可知:
注入一个类型的时候,他的泛型也是参考标准之一,使用父类的类型进行自动注入时,若父类有泛型,会使用带指定泛型的父类来进行自动注入