如果转载文章请注明出处, 谢谢 !
本系列文章是学习完 Spring4.3.8 后的详细整理, 如果有错误请向我指明, 我会及时更正~😝
Spring4.3.8
3.4 依赖注入(DI)
控制反转,我们可以把它看作是一个概念。而依赖注入(Dependency Injection)是控制反转的一种实现方法.
James Shore给出了依赖注入的定义:依赖注入就是将实例变量传入到一个对象中去(Dependency injection means giving an object its instance variables)。
3.4.1 xml 形式
3.4.1.1 使用构造器注入
通过参数顺序, 类型等
<bean id="person" class="com.lanou.domain.Person">
<!--根据参数名称注入-->
<constructor-arg name="name" value="大老王"/>
<!--根据索引index注入-->
<constructor-arg index="1" value="24"/>
<!--根据构造器参数的类型-->
<constructor-arg type="java.lang.String" value="men"/>
</bean>
3.4.1.2 使用属性 setter 方法
public class Person {
private String name;
private int age;
private String gender;
private Car car;
private List list;
private Set set;
private Map map;
private Properties properties;
private Object[] objects;
[属性 setter 方法]
}
简单Bean的注入
<bean name="person" class="com.lanou.domain.Person">
<!-- property 就是一个bean 的属性
name 用来描述属性的名称
value 就是属性值, 一般类型(基本类型和 String)
-->
<property name="name" value="狗蛋儿"/>
<property name="age" value="22"/>
<property name="gender" value="men"/>
</bean>
引用其他Bean
<bean name="car" class="com.lanou.domain.Car"></bean>
<bean name="person" class="com.lanou.domain.Person">
<!--spring 容器内部创建的car 对象给 Person 的 car属性赋值-->
<property name="car" ref="car"/>
</bean>
3.4.1.3 装配 list 集合
<property name="list">
<list>
<value>list1</value>
<ref bean="car"/>
</list>
</property>
3.4.1.4 装配 set
<property name="set">
<set>
<value>set1</value>
<ref bean="car"/>
</set>
</property>
3.4.1.5 装配 map
<property name="map">
<map>
<entry key="m1">
<value>map1</value>
</entry>
<entry key="m2">
<ref bean="car"/>
</entry>
</map>
</property>
3.4.1.5 装配 properties
<property name="properties">
<props>
<prop key="p1">pp1</prop>
<prop key="p2">pp2</prop>
</props>
</property>
3.4.1.6 装配 Object[]
<property name="objects">
<list>
<value>obj1</value>
<ref bean="car"/>
</list>
</property>
3.4.2 注解 Annotation
注解的注入会在XML之前,因此后者配置将会覆盖前者.
配置bean
3.4.2.1 @Component
@Component是所有受 Spring 管理组件的通用形式,泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Component 不推荐使用。
@Component
public class Person {
}
3.4.2.2@Controller
@Controller对应表现层的Bean,也就是Action, 例:
@Controller
@Scope("prototype")
public class UserAction {
}
3.4.2.3 @Respository
用于标注数据访问组件,即DAO组件
@Repository
public class UserDao {
}
3.4.2.4 @Service
用于标注业务层组件
@Service
public class UserServiceImpl {
}
对于扫描到的组件, Spring有默认的命名策略 :
1)使用非限定类名,第一个字母小写
(UserServiceImpl -> userServiceImpl)
2)在注解中通过 value 属性值标识组件的名称
(通常可以将UserServiceImpl -> userService,可以将Impl拿掉,这是一个习惯)
@Service("userService")
public class UserServiceImpl {
}
(3)当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件中声明 <context:component-scan>
:
base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类.
当需要扫描多个包时, 可以使用逗号分隔.
配置 bean 的属性
3.4.2.5 @Autowired
使用@Autowired 注解自动装配, @Autowired 默认按类型装配.
可以在普通setter方法上使用@Autowired注解
public class UserServiceImpl implements UserService{
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
可以将注解应用到构造器和字段上
public class UserServiceImpl implements UserService{
private UserDao userDao;
@Autowired
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
}
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
}
可以将注解应用到任意名称或参数的方法上
public class UserServiceImpl implements UserService{
private UserCatalog userCatalog;
private UserDao userDao;
@Autowired
public void prepare(UserCatalog catalog, UserDao dao){
this.userCatalog = catalog;
this.userDao = dao;
}
可以把指定类型的所有Bean提供给一个数组类型, 集合类型的变量
public class UserServiceImpl implements UserService{
@Autowired
private UserCatalog[] catalogs;
}
xml 中只定义了几个 对应bean
<bean id="userService" class="com.lanou.service.impl.UserServiceImpl"/>
<bean id="dao" class="com.lanou.dao.impl.UserDaoImpl"/>
<bean id="catalog" class="com.lanou.domain.UserCatalog"/>
@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,一旦找不到对应的Bean,自动注入就会失败。若要改变默认的策略或允许null值,可以设置它required属性为false。
public class UserServiceImpl implements UserService{
// xml 中没有定义UserFinder的 bean
@Autowired(required = false)
private UserFinder userFinder;
}
3.4.2.6 @Qualifier
使用@Qualifier调整基于注解的自动注入.
在指定参数上使用@Qualifier,可以缩小类型匹配的范围,更容易为参数找到指定的Bean。
[想使用按名称装配,可以结合@Qualifier注解一起使用]
public class UserServiceImpl implements UserService{
@Qualifier("userD")
@Autowired
private UserDao userD;
}
对应的Bean定义如下所示。
标识值为“userDe”的Bean将会被标记为@Qualifier(“userDe”)的参数所注入:
<bean id="dao" class="com.lanou.dao.impl.UserDaoImpl">
<qualifier value="userD"/>
</bean>
如果全部使用注解, 可以在UserDaoImpl中使用Repository配置
@Repository("userDe")
public class UserDaoImpl implements UserDao{
}
3.4.2.7 @Resource
@Resource 注解和@Autowired一样,也可以标注在字段或属性的setter方法上.
@Resource注解默认按名称装配。
名称可以通过@Resource的name属性指定,如果没有指定name属性,
当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象;
当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。
public class UserServiceImpl implements UserService{
@Qualifier("userD")
@Autowired
private UserDao userD;
@Resource(name = "daoU")
private UserDao userDao;
}
注: 如果没有指定name属性,并且按照默认的名称找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。
3.4.2.8 @Required
@Required注解应用于Bean属性的setter方法,如下:
public class UserServiceImpl implements UserService{
private UserDao userDao;
@Required
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
这个表明Bean的属性值必须在配置中指定,可以通过显示的在Bean定义中指定,也可以使用自动注入。若没有为这个属性指定值,那么容器会抛出一个异常。
<bean id="userService" class="com.lanou.service.impl.UserServiceImpl">
<property name="userDao" ref="dao"/>
</bean>
<bean id="dao" class="com.lanou.dao.impl.UserDaoImpl"/>
3.4.2.8 @PostConstruct & @PreDestroy
生命周期注解
之前的做法是在xml中定义init-method 和 destroy-method方法
public class User {
public User() {
System.out.println("user .. 构造函数");
}
@PostConstruct
public void init(){
System.out.println("I'm init method using @PostConstrut....");
}
@PreDestroy
public void destroy(){
System.out.println("I'm destory method using @PreDestroy.....");
}
}
3.5 扫描
spring2.5为我们引入了组件自动扫描机制,它可以在类路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理.
它的作用和在xml文件中使用bean节点配置组件是一样的。要使用自动扫描机制,我们需要打开以下配置信息:
- 引入context命名空间 需要在xml配置文件中配置以下信息
- 在配置文件中添加context:component-scan标签
<?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">
<!-- 自动扫描指定包及其子包下的所有Bean类 -->
<context:component-scan base-package="com.lanou.domain"/>
在 base-package 指明一个包, 表明自动扫描目录 com.lanou 包及其子包中的注解,当需要扫描多个包时, 可以使用逗号分隔.
其他用法:
<!-- 通过resource-pattern指定扫描的资源 -->
<!--只扫描repository下的类-->
<context:component-scan base-package="com.lanou" resource-pattern="dao/*.class"></context:component-scan>
<!-- 不扫描repository注解的类 。可以配置多个。-->
<context:component-scan base-package="com.lanou" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
<!-- 只扫描repository注解的类。可以配置多个。 -->
<context:component-scan base-package="com.lanou" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
<!-- 不扫描某个接口。可以配置多个。使用assignable类型 -->
<context:component-scan base-package="com.lanou" use-default-filters="true">
<context:exclude-filter type="assignable" expression="com.lanou.dao.UserDao"/>
</context:component-scan>
<!-- 只扫描某个接口。 -->
<context:component-scan base-package="com.lanou" use-default-filters="false">
<context:include-filter type="assignable" expression="com.lanou.dao.UserDao"/>
</context:component-scan>
3.6 Spring 的继承
public class People {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Student extends People {
}
<bean name="people" class="com.lanou.domain.People">
<property name="name" value="111"/>
</bean>
<bean name="student" class="com.lanou.domain.Student"></bean>
public void testExtents(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
// student 打印出来的名字为 null
System.out.println(student.getName());
}
配置文件需要更改
<!-- parent 实现了 spring 容器内部的继承关系
在父类中进行赋值, 子类继承父类内容
-->
<bean name="people" class="com.lanou.domain.People">
<property name="name" value="111"/>
</bean>
<bean name="student" class="com.lanou.domain.Student" parent="people"></bean>
还有其他方式解决 student 的名字赋值问题么?
student 也继承了 people 的 name setter 方法
Spring4.3.8学习[三]
Spring4.3.8学习之 与 Struts2 整合[四]
Spring4.3.8学习之与Hibernate4 整合[五]
Spring4.3.8学习之S2SH 整合[六]