
Spring 全家桶,包括Spring data,springboot,springcloud等等


需求:

下面是普通的代码实现,将child和apple进行强关联,这就出现了一个问题,灵活性不高,如果我想修改,就必须改动源代码
public static void main(String[] args) {
Apple apple1 = new Apple("红富士", "红色", "欧洲");
Apple apple2 = new Apple("绿富士", "绿色", "绿大利");
Apple apple3 = new Apple("蓝富士", "蓝色", "兰博基尼");
Child lily = new Child("lily", apple1);
Child andy = new Child("andy", apple2);
Child luna = new Child("luna", apple3);
lily.eat();
andy.eat();
luna.eat();
}
针对这个问题,Spring应运而生,下面我们使用Spring来实现上述逻辑
Spring
首先,引入Spring的依赖
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>4.3.11.RELEASEversion>
dependency>
dependencies>
下面是几大重要的包

接着在resources下新建applicationContext.xml,增加配置如下:
<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 id="sweetApple" class="com.imooc.imooc.spring.ioc.eneity.Apple">
<property name="title" value="红富士">property>
<property name="origin" value="欧洲">property>
<property name="color" value="红色">property>
bean>
<bean id="sourApple" class="com.imooc.imooc.spring.ioc.eneity.Apple">
<property name="title" value="青苹果">property>
<property name="origin" value="中亚">property>
<property name="color" value="绿色">property>
bean>
<bean id="softApple" class="com.imooc.imooc.spring.ioc.eneity.Apple">
<property name="title" value="金帅">property>
<property name="origin" value="中国">property>
<property name="color" value="黄色">property>
bean>
beans>
然后新建SpringApplication类,看看获取对象
package com.imooc.imooc.spring.ioc.eneity;
import com.imooc.imooc.spring.ioc.Application;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/22 19:34
* @Version 1.0
*/
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext context =new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Apple sweetApple = context.getBean("sweetApple",Apple.class);
System.out.println(sweetApple.getTitle());
}
}
Spring框架有三种配置Bean的方式,分别是 XML配置Bean) ,基于注解配置Bean,基于Java代码配置Bean
下面我们详细学习如何通过XML配置Bean;
而使用XML配置bean,也有三种实例化Bean方法 基于构造方法对象实例化、基于静态工厂实例化、基于工厂实例方法实例化

下面是通过工厂类实例化对象,优势在于隐藏了对象创建的细节。
首先是配置:
<bean id="apple4" class="com.imooc.spring.ioc.factory.AppleStaticFactory" factory-method="CreateSweetApple"/>
<bean id="factoryInstance" class="com.imooc.spring.ioc.factory.ApplyFactoryInstance">bean>
<bean id="apple5" factory-bean="factoryInstance" factory-method="createSweetApple"/>
然后是两个工厂及其方法:
public class ApplyFactoryInstance {
public Apple createSweetApple(){
Apple apple =new Apple();
apple.setOrigin("欧洲");
apple.setColor("红色");
apple.setTitle("红富士");
return apple;
}
}
public class AppleStaticFactory {
public static Apple CreateSweetApple(){
Apple apple =new Apple();
apple.setOrigin("欧洲");
apple.setColor("红色");
apple.setTitle("红富士");
return apple;
}
}
初始化完成后,我们如何从Ioc容器中获取bean呢?有两种方式,分别如下:

另外,其实在xml中 bean有ID和Name两个属性,这两个属性有什么区别呢?
首先,我们来看看他们的相同点:
两者不同点:
示例代码如下:

ApplicationContext-service.xml:
<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 id="bookService" class="com.imooc.spring.ioc.bookshop.service.BookService">
<property name="bookDao" ref="bookDao">property>
bean>
beans>
ApplicationContext-dao.xml:
<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 id="bookDao" class="com.imooc.spring.ioc.bookshop.dao.BookDaoImpl">bean>
beans>
BookDao
package com.imooc.spring.ioc.bookshop.dao;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/24 22:42
* @Version 1.0
*/
public interface BookDao {
public void insert();
}
BookDaoImpl
package com.imooc.spring.ioc.bookshop.dao;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/24 22:42
* @Version 1.0
*/
public class BookDaoImpl implements BookDao{
public void insert() {
System.out.println("向Mysql Book 表插入一条数据");
}
}
bookShopApplication
package com.imooc.spring.ioc.bookshop;
import com.imooc.spring.ioc.bookshop.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/24 22:47
* @Version 1.0
*/
public class bookShopApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:ApplicationContext-*.xml");
BookService bookService = context.getBean("bookService",BookService.class);
bookService.purchase();
}
}
区别在于xml‘中bean参数 一个使用 property 一个使用 constructor-arg
1. 注入List:

2. 注入set

3. 注入map


示例代码:
<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 id="c1" class="com.imooc.spring.ioc.entity.Computer">
<constructor-arg name="brand" value="联想">constructor-arg>
<constructor-arg name="type" value="台式机">constructor-arg>
<constructor-arg name="sn" value="8389283012">constructor-arg>
<constructor-arg name="price" value="3085">constructor-arg>
bean>
<bean id="company" class="com.imooc.spring.ioc.entity.Company">
<property name="rooms">
<set>
<value>2001-总裁办value>
<value>2003-总经理办公室value>
<value>2010-研发部会议室value>
<value>2010-研发部会议室value>
set>
property>
<property name="computers">
<map>
<entry key="dev-880172" value-ref="c1">entry>
<entry key="dev-88173">
<bean class="com.imooc.spring.ioc.entity.Computer">
<constructor-arg name="brand" value="华为">constructor-arg>
<constructor-arg name="type" value="笔记本">constructor-arg>
<constructor-arg name="sn" value="8389283013">constructor-arg>
<constructor-arg name="price" value="5085">constructor-arg>
bean>
entry>
map>
property>
<property name="info">
<props>
<prop key="phone">010-12345678prop>
<prop key="address">湖北省武汉市xx中心prop>
<prop key="website">http:www.baidu.comprop>
props>
property>
bean>
beans>
示例代码:
package com.imooc.spring.ioc;
import com.imooc.spring.ioc.entity.Company;
import com.imooc.spring.ioc.entity.Computer;
import javafx.application.Application;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/24 23:09
* @Version 1.0
*/
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:ApplicationContext.xml");
Company company = context.getBean("company", Company.class);
System.out.println(company);
System.out.println(company.getInfo().getProperty("website"));
// 获取容器内对象名称
String[] beanNames = context.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println(beanName);
System.out.println("类型:"+context.getBean(beanName).getClass().getName());
System.out.println("内容:"+context.getBean(beanName).toString());
}
}
}



配置示例:

首先是IOC容器类:
接口:
package com.imooc.spring.ioc.context;
/**
* ApplicationContext 接口
*
* @Author wangw
* @Date 2022/11/26 22:15
* @Version 1.0
*/
public interface ApplicationContext {
public Object getBean(String beanId);
}
实现类:
package com.imooc.spring.ioc.context;
import com.imooc.spring.ioc.entity.Apple;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* ApplicationContext 实现类,本质就是一个IOC容器
*
* @Author wangw
* @Date 2022/11/26 22:16
* @Version 1.0
*/
public class ClassPathXmlApplicationContext implements ApplicationContext {
private Map iocContainer = new HashMap();
public ClassPathXmlApplicationContext() {
try {
String filePath = this.getClass().getResource("/applicationContext.xml").getPath();
filePath = new URLDecoder().decode(filePath, "UTF-8");
SAXReader reader = new SAXReader();
Document document = reader.read(filePath);
List<Node> nodes = document.getRootElement().selectNodes("bean");
for (Node node : nodes) {
Element element = (Element) node;
String id = element.attributeValue("id");
String className = element.attributeValue("class");
Class class1 = Class.forName(className);
Object obj = class1.newInstance();
List<Node> list = element.selectNodes("property");
for (Node node1 : list) {
Element property = (Element) node1;
String propName = property.attributeValue("name");
String propValue = property.attributeValue("value");
String setMethodName ="set"+propName.substring(0,1).toUpperCase()+propName.substring(1);
System.out.println("准备执行"+setMethodName+"方法注入数据");
Method method = class1.getMethod(setMethodName,String.class);
method.invoke(obj,propValue);
}
iocContainer.put(id, obj);
System.out.println("ioc容器初始化完毕");
System.out.println(iocContainer);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Object getBean(String beanId) {
return iocContainer.get(beanId);
}
}
配置XML:
<beans>
<bean id ="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
<property name="title" value="红富士">property>
<property name="origin" value="欧洲">property>
<property name="color" value="红色">property>
bean>
beans>
实体类:
package com.imooc.spring.ioc.entity;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/26 22:11
* @Version 1.0
*/
public class Apple {
private String title;
private String color;
private String origin;
public Apple() {
}
public Apple(String title, String color, String origin) {
this.title = title;
this.color = color;
this.origin = origin;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
}
启动类:
package com.imooc.spring.ioc;
import com.imooc.spring.ioc.context.ApplicationContext;
import com.imooc.spring.ioc.context.ClassPathXmlApplicationContext;
import com.imooc.spring.ioc.entity.Apple;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/26 22:27
* @Version 1.0
*/
public class Application {
public static void main(String[] args) {
ApplicationContext context =new ClassPathXmlApplicationContext();
Apple apple = (Apple) context.getBean("sweetApple");
System.out.println(apple);
}
}
至此实现效果如下,可以看出其实Spring IoC容器就是通过反射实现的


如果我们需要使用上面几个注解,有个前提条件是需要 开启组件扫描,即

在这里需要注意的是 基于注解配置和基于xml配置的applicationContext.xml有些不同,配置如下:
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.imooc"/>
beans>

在使用按类型装配过程中可能会存在一个问题,就是存在两个相同类型的对象,会存在装配失败的情况,此时可以使用@Primary注解标识其中一个为主要,当注入时就会优先选用这个。
或者我们可以按照名称装配完成注入。
需要注意的是当使用@Resource注解时,有以下情况:
当配置了name时候:直接按照name在IoC容器中注入bean
未配置name时,首先根据属性名称去IoC容器中匹配,匹配上则注入,如果没有匹配上则按照类型去匹配注入,此时同@Autowired

我们使用@Value注解时有几个点需要注意:
第一是一般@Value数据从配置文件读取,所以首先需要增加配置文件,如:

第二是需要在applicationContext.xml增加:

第三则是引用配置,如下:


下面给出示例代码:
Config类:
package com.imooc.spring.ioc;
import com.imooc.spring.ioc.controller.UserController;
import com.imooc.spring.ioc.dao.EmployeeDao;
import com.imooc.spring.ioc.dao.UserDao;
import com.imooc.spring.ioc.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/28 22:36
* @Version 1.0
*/
@Configuration //说明当前类是一个【配置类,用于替代applicationContext.xml
@ComponentScan(basePackages = {"com.imooc"}) //配置这个等同于xml中的content:component-scan
public class Config {
@Bean
public UserDao userDao() {
UserDao userDao = new UserDao();
System.out.println(userDao);
return userDao;
}
@Bean
//先按name尝试注入,不存在则按照类型注入
public UserService userService(UserDao userDao , EmployeeDao employeeDao) {
UserService userService = new UserService();
System.out.println(userService);
System.out.println("注入userDao"+userDao);
userService.setUserDao(userDao);
userService.setEmployeeDao(employeeDao);
return userService;
}
@Bean
public UserController userController(UserService userService) {
UserController userController = new UserController();
System.out.println("注入userService"+userService);
userController.setUserService(userService);
return userController;
}
}
启动类:(首句发生改变,使用 new AnnotationConfigApplicationContext(Config.class))
package com.imooc.spring.ioc;
import javafx.application.Application;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.lang.annotation.Annotation;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/28 22:42
* @Version 1.0
*/
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
System.out.println("-------------------------------------------------------------");
String[] ids= context.getBeanDefinitionNames();
for (String id : ids) {
System.out.println(id+":"+context.getBean(id));
}
}
}
其余类无特殊配置,仅给出一个示例:
package com.imooc.spring.ioc.service;
import com.imooc.spring.ioc.dao.EmployeeDao;
import com.imooc.spring.ioc.dao.UserDao;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/28 22:36
* @Version 1.0
*/
public class UserService {
private UserDao userDao;
private EmployeeDao employeeDao;
public EmployeeDao getEmployeeDao() {
return employeeDao;
}
public void setEmployeeDao(EmployeeDao employeeDao) {
this.employeeDao = employeeDao;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
经过上面基于xml的配置以及基于java Config的配置,可以看出,xml便于维护,但是较复杂,Java Config的注解适用于开发,但不利于维护,所以xml更适合大型项目的协同合作,基于Java Config的注解更适合于敏捷开发,例如:springboot就默认使用这个
import com.imooc.spring.ioc.servie.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
/**
* todo {类简要说明}
*
* @Author wangw
* @Date 2022/11/28 23:20
* @Version 1.0
*/
// 将Junit4的执行权加交由Spring Test,在测试用例执行前自动初始化IoC容器
@RunWith(SpringJUnit4ClassRunner.class)
// ioc初始化过程中通知加载哪个配置文件
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringTestor {
@Resource
private UserService userService;
@Test
public void testUserService(){
userService.createUser();
}
}