文章目录
一、bean的配置
Spring中,xml配置文件的根元素是< beans>,< beans>中可以包含多个< bean>子元素,每一个
< bean>子元素定义了一个Bean,并描述了该Bean如何被装配到Spring容器中。
< bean>子元素中包含多个属性和子元素如下:
- id:Bean的唯一标识符,只有通过它,程序才可以使用
- name:Spring容器通过此属性进行配置和管理,可以通过name为Bean指定多个别名,每个别名之间通过逗号隔开
- class:指定Bean的实现类,它必须使用类的全限定名
- scope:用于设定Bean实例的作用域,其属性值有singleton(单例),prototype(原型),request,session,application,websocket,默认值为singleton
- constructor-arg:< bean>元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的index属性指定构造参数的序号(从0开始),type属性指定构造参数的类型,参数值可以通过ref属性或者value属性直接指定,也可以通过ref或value子元素指定
- property:< bean>元素的子元素,用于调用Bean实例中的setter()方法完成属性赋值,从而完成依赖注入。该元素的name属性指定Bean实例中的响应属性名,ref属性或value属性用于指定参数值
- ref:< constructor-arg>、< property>等元素的属性或子元素,可以用于指定对Bean工厂中某个Bean实例的引用
- value:< constructor-arg>、< property>等元素的属性或子元素,可以用于直接给定一个常量值
- list:用于封装List或数组属性的依赖注入
- set:用于封装Set类型属性的依赖注入
- map:用于封装Map类型属性的依赖注入
- entry:< map>元素的子元素,用于设置一个键值对。其key属性指定字符串类型的键值,ref属性或value属性直接指定其值,也可以通过ref或value子元素指定其值
注:如果在Bean中未指定id和name,那么Spring会将class值当做id使用
如何使用:
1、创建实体类
package pojo;
//User类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
}
package pojo;
import java.util.*;
//Student类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private Properties info;
private String wife;
}
package pojo;
//Address类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address {
private String address;
}
2、创建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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--applicationContext.xml-->
<bean id="address" class="com.study.pojo.Address">
<property name="address" value="西安"/>
</bean>
<bean id="student" class="com.study.pojo.Student">
<!--第一种,普通值注入,直接使用value赋值法-->
<property name="name" value="二十四桥明月夜"/>
<!--第二种,bean注入,使用ref引用-->
<property name="address" ref="address"/>
<!--数组-->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
<value>三国</value>
</array>
</property>
<!--List-->
<property name="hobbys">
<list>
<value>看电影</value>
<value>敲代码</value>
<value>听歌</value>
</list>
</property>
<!--Map-->
<property name="card">
<map>
<entry key="身份证" value="1111111"/>
<entry key="银行卡" value="112321"/>
</map>
</property>
<!--set-->
<property name="games">
<set>
<value>lol</value>
<value>王者荣耀</value>
</set>
</property>
<!--null-->
<property name="wife">
<null/>
</property>
<!--Properties-->
<property name="info">
<props>
<prop key="学号">19010101</prop>
<prop key="性别">男性</prop>
<prop key="username">小明</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
3、测试
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());
/**结果:
* Student{name='二十四桥明月夜', address=Address{address='西安'},
* books=[红楼梦, 西游记, 水浒传, 三国],
* hobbys=[看电影, 敲代码, 听歌],
* card={身份证=1111111, 银行卡=112321},
* game=[lol, 王者荣耀],
* info={学号=19010101,
* 性别=男性,
* password=123456,
* username=小明},
* wife='null'}
*/
}
二、Bean的作用域
在Spring容器中创建一个Bean实例时,我们需要考虑Bean的作用域,是否每次使用这个对象的时候,都被容器重新创建,还是一直指向第一次创建的实例对象。
重点需要掌握的就是singleton和prototype
- singleton:单例,使用singleton定义的Bean在Spring容器中将只有一个实例,也就是说,无论有多少个Bean引用它,始终指向同一个对象,这也是Spring容器默认的作用域
- prototype:原型,每次通过Spring容器获取prototype定义的Bean时,容器都会创建一个新的Bean实例
还有request、session、globalSession、application、websocket 5种作用域
测试常用的作用域
public class Scope {
}
<?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="scope" class="Scope" scope="singleton"/>
<bean id="scope1" class="Scope" scope="prototype"/>
</beans>
public class test {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(context.getBean("scope"));
System.out.println(context.getBean("scope"));
System.out.println("==========================");
System.out.println(context.getBean("scope1"));
System.out.println(context.getBean("scope1"));
}
}
结果
比对地址,就可以得出,单例和原型的区别!
三、基于Annotation的装配
在Spring中,尽管使用xml配置文件可以实现Bean的装配工作,但如果应用中有很多Bean,就会导致xml配置文件过于臃肿,给以后的维护和升级代码一定的困难。为此,Spring提供了很方便的Annotation(注解)支持。
- @Component:可以使用此注解描述Spring中的Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次,使用时只需要将该注解标注在相应类上即可。
- @Repository:用于数据访问层(DAO层)的类标识为Spring中的Bean,其功能与@Component相同
- @Service:通常作用在业务层(Service层),用于将业务层的类标识为Spring中的Bean,其功能与@Component相同
- @Controller:通常作用在控制层(如Spring MVC的Controller层),用于将控制层的类标识为Spring中的Bean,其功能与@Component相同
- @Autowired:用于对Bean的属性变量、属性的setter()方法及构造方法进行标注,配合对应的注解完成Bean的自动配置工作。默认按照Bean的类型进行装配
- @Resource:作用与@Autowired一样,区别在于@Autowired默认按Bean类型装配,而@Resource默认按照Bean实例名称进行装配。
@Resource中有两个重要属性:name和type。Spring将name属性解析为Bean实例名称,type属性解析为Bean实例类型。
若指定name属性,则按照实例名称进行装配;
若指定type属性,则按Bean类型进行装配;
若都不指定,则先按Bean实例名称装配,不能匹配时再按照Bean类型进行装配;若都无法匹配,则抛出异常
- @Qualifier:与 @Autowired注解搭配使用,会将默认的按Bean类型装配修改为按Bean的实例名称装配,Bean的实例名称由@Qualifier注解的参数指定
使用
创建接口和接口实现类
//UserController类,特意删除了接口,用来比较
@Controller("UserControllerImpl")
public class UserControllerImpl {
public void save() {
System.out.println("UserControllerImpl.sava()");
}
}
//UserMapper接口
public interface UserMapper {
public void save();
}
//UserMapperImpl类
@Repository("UserMapperImpl")
public class UserMapperImpl implements UserMapper {
@Override
public void save() {
System.out.println("UserMapper.sava()");
}
}
//UserService接口
public interface UserService {
public void save();
}
//UserServiceImpl类
@Service("UserServiceImpl")
public class UserServiceImpl implements UserService{
@Override
public void save() {
System.out.println("UserServiceImpl.sava()");
}
}
在applicationContext.xml中注册
<!--开启注解处理器-->
<context:annotation-config/>
<!--开启自动扫描包-->
<context:component-scan base-package="dao"/>
<context:component-scan base-package="service"/>
<context:component-scan base-package="contorller"/>
测试:
public class test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
context.getBean("UserMapperImpl", UserMapper.class).save();
context.getBean("UserServiceImpl", UserService.class).save();
context.getBean("UserControllerImpl", UserControllerImpl.class).save();
}
}
结果:
上面的三种注解方式,都可以使用Autowired替换,达到同样的效果,但是为了开发规范,建议使用各个类的注解方式,规范代码编写。
value的使用:
@Component
public class User {
//value相当于
//<property name="name" value="二十四桥明月夜"/>
//也可以在set方法中注解
@Value("二十四桥明月夜")
public String name;
//相同
//public String name = "二十四桥明月夜";
}
<?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 base-package="com.study.pojo"/>
<context:annotation-config/>
</beans>
测试:
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = context.getBean("user", User.class);
System.out.println(user.name);
}
}
@Autowired的使用:
public class Cat {
public void shout(){
System.out.println("miao");
}
}
public class Dog {
public void shout(){
System.out.println("wang");
}
}
public class People {
//如果显式的定义了Autowired的required属性为false,说明这个对象可以为空,否则不可以
@Autowired
private Cat cat;
@Autowired
@Qualifier(value = "dog")//指定bean中的id名字,在Bean中必须有它的映射,且id=dog
private Dog dog;
private String name;
}
<?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:annotation-config/>
<bean id="cat" class="com.study.pojo.Cat"/>
<bean id="dog" class="com.study.pojo.Dog"/><!--与实体类中注解装配的id相对应-->
<bean id="dog1" class="com.study.pojo.Dog"/><!--多加一个bean,用于测试-->
<bean id="people" class="com.study.pojo.People"/>
</beans>
测试:
public class MyTest {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people", People.class);
people.getDog().shout();
people.getCat().shout();
}
}
结果:
四、自动装配
Spring的< bean>元素中包含一个autowire属性,可以通过设置autowire属性值来自动装配Bean。
- default:默认值,由< bean>的上级标签< beans>的default-autowire属性值确定。例如< beans default-autowire=“byName”>,该< bean>元素中的autowire属性对应的属性值为byName
- byName:根据属性的名称自动装配。容器将根据名称查找与属性完全一致的Bean,并将其属性自动装配
- byType:根据属性的数据类型自动装配,如果一个Bean的数据类型兼容另一个Bean中属性的数据类型,则自动装配
- constructor:根据构造函数参数的数据类型进行byType模式的自动装配
- no:在默认情况下,不适用自动装配,Bean依赖必须通过ref元素定义
byName和ByType:
创建的实体类在Autowried中
- byName自动装配
<bean id="cat" class="pojo.Cat" />
<bean id="dog" class="pojo.Dog"/>
<bean id="dog1" class="pojo.Dog"/>
<!--byName:会自动在容器上下文中查找,和直接对象set方法后面的值所对应的bean-id-->
<bean id="people" class="pojo.People" autowire="byName"/>
<!--相当于-->
<bean id="people" class="pojo.People">
<property name="cat" ref="cat"/><!--引用的是上面第一行的cat-->
<property name="dog" ref="dog"/><!--引用的是上面第二行的dog-->
</bean>
- byType自动装配
<bean id="cat" class="pojo.Cat" />
<bean id="dog" class="pojo.Dog"/>
<bean id="dog1" class="pojo.Dog"/><!--会自动报错,提示无法匹配-->
<!--byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean,且保证id唯一-->
<bean id="people" class="pojo.People" autowire="byType"/>
报错的图片:
在注册bean的时候,可以省略id,自动装配
小结:
- byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性和set方法的值一致(不区分大小写)
- byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致