目录
1. 什么是Spring-DI
DI(dependency injection ):依赖注入,目的是给对象中的属性进行赋值
通过IOC(控制反转)把对象的创建交给Spring容器,但是都是通过无参构造,对象拥有的属性都是初始值,没有进行赋值,通过Spring-DI可以实现属性的赋值。
2. 依赖注入方式
(1)创建一个类,设置属性,并提供set方法
public class UserDao{
private String username;
private int password;
public void setUsername(String username) {
System.out.println("设置username。。。");
this.username = username;
}
public void setPassword(int password) {
System.out.println("设置password。。。");
this.password = password;
}
}
(2) 在配置文件中,该类所对应的bean中添加标签
property:表示为类中属性注入值,调用的为set方法
name:表示属性名
value:注入基本类和字符串类型时使用value
<bean id="userDao" class="com.lcy.demo.UserDao">
<property name="username" value="lcy"/>
<property name="password" value="123456"/>
</bean>
(3)测试
@Test
public void testUserDao(){
//读取配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean对象
IUserDao userDao = (IUserDao) ac.getBean("userDao");
}
3. 依赖注入的类型以及各种类型的注入
依赖注入的类型有:基本数据类型, 字符串类型,引用类型,集合类型。
3.1 注入基本数据类型和字符串--value
<property name="name" value="lcy"/>
<property name="age" value="22"/>
3.2 注入引用类型--ref
Student 中有属性Clazz
public class Student {
private String name;
private int age;
private Clazz cla;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setCla(Clazz cla) {
this.cla = cla;
}
}
public class Clazz {
private int id;
private String tea;
public void setId(int id) {
this.id = id;
}
public void setTea(String tea) {
this.tea = tea;
}
@Override
public String toString() {
return "Clazz{" +
"id=" + id +
", tea='" + tea + '\'' +
'}';
}
}
其中age需要的为int类型,但在在xml中,数字类型也要加双引号,这是xml的规定
<bean id="student" class="com.lcy.demo.Student">
<property name="name" value="lcy"/>
<property name="age" value="22"/>
<property name="cla" ref="cla"/>
</bean>
<bean id="cla" class="com.lcy.demo.Clazz">
<property name="id" value="151"/>
<property name="tea" value="ykq"/>
</bean>
3.3 集合类型
private List<String> list;
private int[] arr;
private Set<String> set;
private Map<String, String> map;
<property name="list">
<list>
<value>听音乐</value>
<value>睡觉觉</value>
<value>打游戏</value>
</list>
</property>
<property name="arr">
<array>
<value>0</value>
<value>1</value>
<value>2</value>
</array>
</property>
<property name="set">
<set>
<value>吃饭饭</value>
<value>吃饭饭</value>
<value>睡觉觉</value>
</set>
</property>
<property name="map">
<map>
<entry key="001" value="刘备"/>
<entry key="002" value="关羽"/>
<entry key="003" value="张飞"/>
</map>
</property>
测试:输出结果为
Student{name='lcy', age=22, cla=Clazz{id=151, tea='ykq'}, list=[听音乐, 睡觉觉, 打游戏], arr=[0, 1, 2], set=[吃饭饭, 睡觉觉], map={001=刘备, 002=关羽, 003=张飞}}
4. 构造器注入
package com.lcy.demo;
/**
* @Author Lcy
* @Date 2022/6/13
*/
public class User {
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
<bean id="user" class="com.lcy.demo.User">
<constructor-arg name="username" value="lcy"/>
<constructor-arg name="password" value="root"/>
</bean>
如果严格按照构造方法的参数顺序,则name属性可以省略
<bean id="user" class="com.lcy.demo.User">
<constructor-arg value="lcy"/>
<constructor-arg value="root"/>
</bean>
5. 自动注入Autowire
在bean中有一个属性为 autowire ,表示自动注入,其中有值
byteName:按照名称进行注入
byType:按类型进行注入
constructor:按照构造方法进行注入
default:默认注入方式
1. 为什么需要autowire
因为在bean很多或者自定义的类很多的情况下,就需要在xml文件中一直写bean并且还要将每一个属性set(构造方法)入参的方式引入bean里面,这样的耦合性变高,后期也不容易进行维护。
2. 注入实例
(1)autowire=“byname”;把与Bean的属性具有相同名字的其他Bean自动装配到Bean的对应属性中
public class School {
private String name;
private String address;
}
public class Student {
private School school;
}
<bean id="school" class="com.lcy.demo3.School">
<property name="name" value="清华"/>
<property name="address" value="北京"/>
</bean>
<bean id="student" class="com.lcy.demo3.Student" autowire="byName"/>
如上所述,只要属性名称和Bean的名称可以对应,那么在student的Bean中就可以使用byName来自动装配。
如果不使用属性名称来对应,你也可以选择使用类型来自动装配。把与Bean的属性具有相同类型的其他Bean自动装配到Bean的对应属性中。即---》byType
而constructor:是把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean构造器的对应入参中。值的注意的是,具有相同类型的其他Bean这句话说明它在查找入参的时候,还是通过Bean的类型来确定。
默认情况下,default-autowire属性被设置为none,标示所有的Bean都不使用自动装配,除非Bean上配置了autowire属性。
如果你需要为所有的Bean配置相同的autowire属性,有个办法可以简化这一操作。
例如:在根元素Beans上增加属性default-autowire="byType"。
|
6. 注解@Autowired
从Spring2.5开始,开始支持使用注解来自动装配Bean的属性。它允许更细粒度的自动装配,我们可以选择性的标注某一个属性来对其应用自动装配。
使用注解记得在配置文件中添加包扫描:
<context:component-scan base-package="需要扫描的包"/>
注意点
1. 默认情况下,@Autowired其所标注的属性必须是可装配的。如果没有Bean可以装配到Autowired所标注的属性或参数中,那么你会看到NoSuchBeanDefinitionException
的异常信息。
2. @Autowired默认使用byType来装配属性,如果匹配到类型的多个实例,可以使用@Qualfier与其配合来确定装配哪一个
@Repository
public interface IUserDao {
void show();
}
@Repository
public class UserDao implements IUserDao{
@Override
public void show() {
System.out.println("UserDao中的shou()被调用");
}
}
@Repository
public class UserDao2 implements IUserDao{
@Override
public void show() {
System.out.println("UserDao2中的shou()被调用");
}
}
@Controller
public class UserController {
@Autowired
@Qualifier(value = "userDao2")
private IUserDao IuserDao;
public void fun(){
IuserDao.show();
}
}
@Controller+@Respository+@Service+@Component
没有区别: 他们的底层都是用的@Component
实际意思就在于区分层的。
@Controller控制层
@Respository持久化层
@Service 业务层
@Component 最底层的bean注解。