Spring(二)——IOC
概念
1.什么是IOC
- 控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理
- 目的:降低耦合度
2.IOC底层原理
xml 解析、工厂模式、反射
IOC接口
1.IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂
2.Spring 提供 IOC 容器实现两种方式:(两个接口)
- BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用(加载配置文件时不创建对象,获取对象时才创建)
- ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用(加载配置文件时就会创建对象)
IOC操作Bean管理
什么是Bean管理
- Spring 创建对象
- Spring 注入属性
Bean管理操作方式
基于 xml 配置文件方式实现
set方法
构造方法
基于注解方式实现
xml注入
(1)xml方式创建对象
<!--配置User类对象创建-->
<bean id="user" class="com.atguigu.spring5.User"></bean>
在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
常用属性
id属性:唯一标识
class属性:类全路径(包类路径)
默认执行无参数构造方法完成对象创建
(2)xml方式注入属性
DI:依赖注入,就是注入属性
- set方法注入
- 创建类,定义属性和对应set方法
- 在 spring 配置文件先配置对象创建,再配置属性注入
Book.java
package com.atguigu.spring5;
public class Book {
private String bname;
private String bauthor;
public void setBname(String bname) {
this.bname = bname;
}
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
}
TestSpring5.java
package com.atguigu.spring5.testdemo;
import com.atguigu.spring5.Book;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring5 {
@Test
public void testBook(){
//加载spring配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
//获取配置创建的对象
Book book=context.getBean("book", Book.class);
System.out.println(book);
book.testdemo();
}
}
xml
<?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">
<!--配置Book类对象创建-->
<bean id="book" class="com.atguigu.spring5.Book">
<!--使用 property 完成属性注入
name:类里面属性名称
value:向属性注入的值
-->
<property name="bname" value="计算机网络原理"></property>
<property name="bauthor" value="小谢"></property>
</bean>
</beans>
- 有参构造函数注入
- 创建类,定义属性,创建属性对应有参数构造方法
- 在 spring 配置文件中进行配置
Order.java
package com.atguigu.spring5;
public class Order {
private String oname;
private String address;
public Order(String oname, String address) {
this.oname = oname;
this.address = address;
}
public void orderTest(){
System.out.println(oname + "::" + address);
}
}
TestSpring5.java
package com.atguigu.spring5.testdemo;
import com.atguigu.spring5.Book;
import com.atguigu.spring5.Order;
import com.atguigu.spring5.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring5 {
@Test
public void testOrder(){
//加载spring配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
//获取配置创建的对象
Order order=context.getBean("order", Order.class);
System.out.println(order);
order.orderTest();
}
}
xml
<?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">
<!--3配置Order类对象创建-->
<bean id="order" class="com.atguigu.spring5.Order">
<constructor-arg name="oname" value="北京烤鸭"></constructor-arg>
<constructor-arg name="address" value="陕西"></constructor-arg>
</bean>
</beans>
- P名称空间注入(了解)
- 添加P名称空间
xmlns:p="http://www.springframework.org/schema/p"
- 属性注入
xml
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--P名称空间注入-->
<bean id="book" class="com.atguigu.spring5.Book" p:bname="计算机网络原理" p:bauthor="小谢">
</bean>
</beans>
xml注入其他类型属性
1.注入字面量
(1) null值
xml
<property name="bname">
<null/>
</property>
(2) 属性值包含特殊符号
方法一:转义符号
方法二:CDATA
xml(CDATA)
<property name="bname">
<value><![CDATA[<<平凡的世界>>]]></value>
</property>
2.注入属性-外部bean
UserService调用UserDao接口的实现类UserServiceImpl的方法(注入对象)
UserService.java
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import com.atguigu.spring5.dao.UserDaoImpl;
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println("service add>>>>>>>>>>>>>>>");
userDao.update();
}
}
xml
<?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="UserService" class="com.atguigu.spring5.service.UserService">
<property name="userDao" ref="UserDaoImpl"></property>
</bean>
<bean id="UserDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>
</beans>
3.注入属性-内部bean
一对多关系:部门和员工,一个部门有多个员工,一个员工属于一个部门
部门类
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
}
员工类
public class Emp {
private String ename;
private String gender;
//员工属于某一个部门,使用对象形式表示
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
}
xml
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--设置对象类型属性-->
<property name="dept">
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
4.注入属性-级联赋值
xml(法一)
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<property name="dname" value="财务部"></property>
</bean>
xml(法二)
先创建dept的get方法(下面会将部门赋值为技术部)
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
<property name="dept.dname" value="技术部"></property>
</bean>
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<property name="dname" value="财务部"></property>
</bean>
5.注入数组、集合类型属性
STU.java
public class Stu {
//1 数组类型属性
private String[] courses;
//2 list 集合类型属性
private List<String> list;
//3 map 集合类型属性
private Map<String, String> maps;
//4 set 集合类型属性
private Set<String> sets;
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
}
xml
<bean id="stu" class="com.atguigu.spring5.collectiontype.Stu">
<!--数组类型属性注入-->
<property name="courses">
<array>
<value>java 课程</value>
<value>数据库课程</value>
</array>
</property>
<!--list 类型属性注入-->
<property name="list">
<list>
<value>张三</value>
<value>小三</value>
</list>
</property>
<!--map 类型属性注入-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<!--set 类型属性注入-->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
</bean>
6.在集合中设置对象类型值
<bean id="stu" class="com.atguigu.spring5.collectiontype.Stu">
<property name="list">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean id="course1" class="com.atguigu.spring5.collectiontype.Course">
<property name="cname" value="Spring5 框架"></property>
</bean>
<bean id="course2" class="com.atguigu.spring5.collectiontype.Course">
<property name="cname" value="MyBatis 框架"></property>
</bean>
7.提取注入
引入名称空间util
<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<util:list id="bookList">
<value>易筋经</value>
<value>九阴真经</value>
<value>九阳神功</value>
</util:list>
<!--2 提取 list 集合类型属性注入使用-->
<bean id="book" class="com.atguigu.spring5.collectiontype.Book">
<property name="list" ref="bookList"></property>
</bean>
</beans>
FactoryBean
两种bean
普通bean:在配置文件中定义bean类型就是返回类型
工厂 bean:在配置文件定义bean类型可以和返回类型不一样
步骤
- 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
- 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
MyBean.java
package com.atguigu.spring5.factorybean;
import com.atguigu.spring5.Book;
import org.springframework.beans.factory.FactoryBean;
public class MyBean implements FactoryBean<Book> {
@Override
public Book getObject() throws Exception {
Book book=new Book();
book.setBname("abc");
return book;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
Test.java
@Test
public void test3(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
Book book=context.getBean("myBean", Book.class);
System.out.println(book);
}
xml
<?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="myBean" class="com.atguigu.spring5.factorybean.MyBean"></bean>
</beans>
Bean作用域
在Spring里面,设置创建bean实例是单实例还是多实例
在Spring里面,默认情况下,bean是单实例对象
在bean标签中通过scope设置单实例或多实例
单实例:scope="singleton"
多实例:scope="prototype"
设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象
设置 scope 值是 prototype 时候,在调用getBean 方法时候创建多实例对象
Bean生命周期
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(4)bean 可以使用了(对象获取到了)
(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
Orders
public class Orders {
//无参数构造
public Orders() {
System.out.println("第一步 执行无参数构造创建 bean 实例");
}
private String oname;
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用 set 方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第三步 执行初始化的方法");
}
//创建执行的销毁的方法
public void destroyMethod() {
System.out.println("第五步 执行销毁的方法");
}
}
Test.java
@Test
public void testBean3() {
// ApplicationContext context =
// new ClassPathXmlApplicationContext("bean4.xml");
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean4.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步 获取创建 bean 实例对象");
System.out.println(orders);
//手动让 bean 实例销毁
context.close();
}
xml
<bean id="orders" class="com.atguigu.spring5.bean.Orders" initmethod="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手机"></property>
</bean>
xml自动装配
根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入
bean标签中autowire属性
- 通过属性名称注入:autowire="byName",(注入值 bean 的 id 值和类属性名称一样,比如下面dept和.java文件中dept名称相同)
- 通过属性类型注入:autowire="byType",(不能存在多个相同类型的bean)
xml(ByName)
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName"></bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
xml(ByType)
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType"></bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
注解操作
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化 xml 配置
Spring针对Bean管理中创建对象提供注解
(1)@Component
(2)@Service
(3)@Controller
(4)@Repository
上面四个作用相同
注解方式创建对象
引入依赖
spring-aop-5.3.22.jar
开启组件扫描(引入context名称空间,如果扫描多个包,多个包用逗号隔开)
创建类,在类上添加创建类的注解
UserServiceTest.java
package com.atguigu.spring5.service;
import org.springframework.stereotype.Component;
//value可以不写,不写时默认为类名,首字母小写
@Component(value = "userServiceTest") //<bean id="userServiceTest"...class...>
public class UserServiceTest {
public void add(){
System.out.println("hhhhhhhhhhhhhhhhh");
}
}
Test.java
@Test
public void test3() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml");
UserServiceTest userServiceTest = context.getBean("userServiceTest", UserServiceTest.class);
System.out.println(userServiceTest);
userServiceTest.add();
}
xml
<?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">
<!--扫描atguigu下的所有-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
</beans>
组件扫描细节配置
扫描包下所有类
<!--例1
默认扫描全部
-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
只扫描Controller注解
<!--例2
use-defaultfilters="false"不使用默认,使用自己配置的
context:include-filter设置扫描哪些内容
type="annotation"根据注解扫描
-->
<context:component-scan base-package="com.atguigu" use-defaultfilters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
不扫描Controller注解
<!--例3
context:exclude-filter设置不扫描哪些内容
-->
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
注解方式注入属性
(1)@Autowired:根据属性类型进行自动装配
(2)@Qualifier:根据名称进行注入
(3)@Resource:可以根据类型注入,也可以根据名称注入
(4)@Value:注入普通类型属性
@Autowired
- 类前添加注解注解创建 service 和 dao 对象
- 在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解
UserDaoImpl.java
package com.atguigu.spring5.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("dao add....................");
}
}
UserService.java
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import com.atguigu.spring5.dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
//不需要添加set方法
@Autowired
private UserDao userDao;
public void add(){
System.out.println("service add........");
userDao.add();
}
}
Test.java
@Test
public void test3() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml");
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
@Qualifier
和@Autowired 一起使用
UserDaoImpl.java
package com.atguigu.spring5.dao;
import org.springframework.stereotype.Repository;
@Repository(value = "userDaoImpl3")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("dao add....................");
}
}
UserService.java
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import com.atguigu.spring5.dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class UserService {
//不需要添加set方法
@Autowired
@Qualifier(value = "userDaoImpl3")
private UserDao userDao;
public void add(){
System.out.println("service add........");
userDao.add();
}
}
@Resource
Resource(不建议使用),是java自身提供的,其余几个是spring提供
//根据类型
@Resource
private UserDao userDao;
//根据名称
@Resource(name="userDaoImpl3")
private UserDao userDao;
@Value
@Value(value = "abc")
private String name;
完全注解开发
创建配置类代替xml配置文件
SpringConfig.java
package com.atguigu.spring5.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration //作为配置类代替xml配置文件
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig {
}
Test.java
@Test
public void test3() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
标签:xml,Spring,void,bean,import,IOC,public,属性
From: https://www.cnblogs.com/LoginX/p/Login_X46.html