1.spring的介绍
spring的2大核心思想:
ioc: 控制反转,就是工厂模式。 将对象的创建和销毁交给了spring
aop:面向切面的编程,就是动态代理。 在不修改源码的情况下,对功能进行增强。
2.spring的ioc
2.1 工厂模式
2.1.2 反射解耦
基于多个实现类需要进行功能切换,我们只需要修改配置文件,不需要改java代码,所以不需要重新编译。
UserServlet
package com.itheima.web;
import com.itheima.service.UserService;
import com.itheima.service.impl.UserServiceImpl;
import com.itheima.service.impl.UserServiceImpl2;
import java.util.ResourceBundle;
public class UserServlet {
public static void main(String[] args) {
//请求过来,调用servlet的service
//UserService userService = new UserServiceImpl2();
//读取配置文件的内容
ResourceBundle rb = ResourceBundle.getBundle("beans");
String classPath = rb.getString("classPath");
UserService userService = null;
try {
userService = (UserService) Class.forName(classPath).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
userService.login();
}
}
UserService
package com.itheima.service;
public interface UserService {
public void login();
}
UserServiceImpl
package com.itheima.service.impl;
import com.itheima.service.UserService;
public class UserServiceImpl implements UserService {
@Override
public void login() {
System.out.println("登录功能");
}
}
UserServiceImpl2
package com.itheima.service.impl;
import com.itheima.service.UserService;
public class UserServiceImpl2 implements UserService {
@Override
public void login() {
System.out.println("登录功能扩展");
}
}
beans.properties
classPath=com.itheima.service.impl.UserServiceImpl2
2.1.2 多例工厂模式
bean.properties
userService=com.it.service.impl.UserServiceImpl
roleService=com.it.service.impl.RoleServiceImpl
BeansFacoty
package com.it.utils;
import com.it.service.RoleService;
import com.it.service.UserService;
import java.util.ResourceBundle;
/**
* 工厂模式:专门用来创建java对象的工具类。
*
* 将java对象的创建由new的方式 替换成了 反射+配置的方式来创建对象。
*
*
* 工厂模式的好处:
* 1.解耦
* 2.可以对java中的对象进行管理。
*
*
* 注意:
* 在没有解耦的情况下,我们以前使用对象,都是自己new
* 现在有了工厂模式,我们使用对象,都是工厂去创建,我们从工厂去获取。
* 对象的创建权利由我们自己创建,交给了工厂创建。这就是ioc
*
*/
public class BeansFactory {
public static Object getBean(String beanName){
//1.读取配置
ResourceBundle rb = ResourceBundle.getBundle("beans");
String classPath = rb.getString(beanName);
//2.反射机制创建对象
Object obj = null;
try {
obj = Class.forName(classPath).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
public static void main(String[] args) {
UserService userService = (UserService) getBean("userService");
System.out.println(userService);
RoleService roleService = (RoleService)getBean("roleService");
System.out.println(roleService);
}
}
2.1.3 单例工厂
package com.it.utils;
import com.it.service.RoleService;
import com.it.service.UserService;
import java.util.HashMap;
import java.util.ResourceBundle;
import java.util.Map;
/**
* 工厂模式:专门用来创建java对象的工具类。
*
* 将java对象的创建由new的方式 替换成了 反射+配置的方式来创建对象。
*
*
* 工厂模式的好处:
* 1.解耦
* 2.可以对java中的对象进行管理。
* 单例和多例
*
* 单例:一个类创建的对象只有一个。节省资源。
* 多例:一个类创建的对象可以有多个。
*
*
* 如果存在线程安全问题的情况下,不能采用单例。
* 什么情况下会出现线程安全问题?
* 1.多并发
* 2.多个线程抢占一个资源,并且做了修改。
*
*
* 注意:
* 在没有解耦的情况下,我们以前使用对象,都是自己new
* 现在有了工厂模式,我们使用对象,都是工厂去创建,我们从工厂去获取。
* 对象的创建权利由我们自己创建,交给了工厂创建。这就是ioc
*
*/
public class BeansFactory {
/**
* 多例工厂
*
* 此时我们的工厂创建的是service对象
* 1.是否是并发的? 是。
* 2.是否涉及多个线程抢占一个资源,并且修改了service。 不涉及service的成员变量的更改
*
* 是否存在线程安全问题呢?不存在
* 使用单例,性能更好。
*
*
* @param beanName
* @return
*/
public static Object getBean(String beanName){
//1.读取配置
ResourceBundle rb = ResourceBundle.getBundle("beans");
String classPath = rb.getString(beanName);
//2.反射机制创建对象
Object obj = null;
try {
obj = Class.forName(classPath).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
private static Map<String,Object> beansMap = new HashMap<>();
/**
* 单例工厂
* 第一次创建对象,后续都是获取第一次创建的对象。
*
* 1.声明变量,接受创建的对象。
* 2.优先从map中获取,如果有,直接返回。如果没有,创建
*
*
*
*
*
* @param beanName 需要创建的对象的名字
* @return 返回创建的对象,如果对象创建失败,返回null
*/
public static Object getBean2(String beanName){
Object obj = beansMap.get(beanName);
if(obj==null){
//第一次创建
//1.读取配置
ResourceBundle rb = ResourceBundle.getBundle("beans");
String classPath = rb.getString(beanName);
//2.反射机制创建对象
try {
obj = Class.forName(classPath).newInstance();
//保存到map,方便下次直接获取
beansMap.put(beanName,obj);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return obj;
}
public static void main(String[] args) {
UserService userService = (UserService) getBean2("userService");
UserService userService2 = (UserService) getBean2("userService");
System.out.println(userService);
System.out.println(userService2);
// RoleService roleService = (RoleService)getBean("roleService");
// System.out.println(roleService);
}
}
2.1.4 单例工厂和多例工厂的区别
多例:
1.什么时候用,什么时候创建。
2.一旦创建成功,工厂想要再次操作这个对象,可不可以? 不可以的。
单例:
1.可以第一次用的时候创建,也可以先全部创建好。
2.一旦创建成功,工厂想要再次操作这个对象,可不可以? 可以,只要从map中获取即可。
2.2 spring的使用
2.2.1 spring的入门
步骤:
1.引入spring-context 依赖,spring的ioc核心依赖。
2.编译spring的配置xml
3.通过spring工厂获取对象
1.pom.xml引入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
</dependencies>
2.编写spring的applicationContext.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 definitions here -->
<bean id="userService" class="com.it.service.impl.UserServiceImpl"></bean>
</beans>
3.通过spring的工厂获取对象
package com.it.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
public static void main(String[] args) {
//1.创建spring的工厂
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//2.通过spring的工厂获取对象
Object userService = ac.getBean("userService");
System.out.println(userService);
}
}
2.2.2 spring的工厂类(了解)
BeanFactory: spring工厂的顶层接口
applicationContext: BeanFactory的子接口
FileSystemXmlApplicationContext: 基于绝对路径的xml的工厂
ClassPathXmlApplicationContext: 基于相对路径的xml的工厂
2者的区别就是:创建(单例)对象的时间不一样
BeanFactory: 什么时候使用,什么时候创建
applicationContext: 工厂初始化时,全部创建成功
2.2.3 spring的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">
<!-- bean definitions here -->
<!--
bean标签: 创建对象,将对象装配到spring容器(泛指spring工厂类)。
id: 对象的唯一标识
class:实现类的路径,底层就是通过反射机制创建对象的。
init-method: 对象创建时,要调用的初始化方法
destroy-method: 对象销毁时,要调用的销毁方法
scope:
singleton: 单例(默认)
prototype: 多例
对象的生命周期:
applicationContext: 工厂初始化时,对象就创建完毕。(单例情况下)
单例:
工厂初始化时创建对象。
只要工厂存在,对象就存在。
工厂销毁,对象销毁。
多例:
什么时候用,什么时候创建。
工厂存在,对象存在。
工厂销毁,对象不销毁。对象只能等待垃圾回收机制回收。
-->
<bean id="userService" scope="prototype" init-method="init" destroy-method="destroy" class="com.it.service.impl.UserServiceImpl"></bean>
</beans>
test:
package com.it.test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class SpringTest {
public static void main(String[] args) {
System.out.println("**************工厂初始化start*********************");
//1.创建spring的工厂
//ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// Resource resource = new ClassPathResource("applicationContext.xml");
// BeanFactory ac = new XmlBeanFactory(resource);
System.out.println("**************工厂初始化end*********************");
//2.通过spring的工厂获取对象
Object userService = ac.getBean("userService");
Object userService2 = ac.getBean("userService");
System.out.println(userService);
System.out.println(userService2);
//销毁工厂
System.out.println("*************销毁工厂*********************8");
ac.close();
}
}
2.2.4 spring创建对象的3种方式
1.默认无参构造
2.工厂类的静态方法
3.工厂类的动态方法
applicationContext.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">
<!--
spring创建对象的4种方式
1.默认无参构造
2.工厂类的静态方法
3.工厂类的动态方法
4.BeanFactory接口方式,ssm整合再去介绍
-->
<!-- 默认无参构造方式-->
<bean id="userService" class="com.it.service.impl.UserServiceImpl"></bean>
<!-- 工厂类的静态方式 -->
<bean id="userService2" class="com.it.utils.BeanFactory" factory-method="getUserService"></bean>
<!-- 工厂类的动态方法-->
<bean id="factoryBean2" class="com.it.utils.BeanFactory2"></bean>
<bean id="userService3" factory-bean="factoryBean2" factory-method="getUserService" ></bean>
</beans>
UserServiceImpl
package com.it.service.impl;
import com.it.service.UserService;
public class UserServiceImpl implements UserService {
public UserServiceImpl() {
System.out.println("UserServiceImpl的无参构造被调用了");
}
}
BeanFactory工厂类的静态方法
package com.it.utils;
import com.it.service.UserService;
import com.it.service.impl.UserServiceImpl;
public class BeanFactory {
public static UserService getUserService(){
System.out.println("工厂类的静态方法");
return new UserServiceImpl();
}
}
BeansFactroy2工厂类的动态方法
package com.it.utils;
import com.it.service.UserService;
import com.it.service.impl.UserServiceImpl;
public class BeanFactory2 {
public UserService getUserService(){
System.out.println("工厂类的静态方法");
return new UserServiceImpl();
}
}
2.2.5 spring的DI
Dependency Injection (依赖注入):spring创建对象的时候,给对象的属性赋值,就是依赖注入。
2.2.5.1 有参构造
UserDao
package com.it.dao;
public interface UserDao {
public void findUserByUser();
}
UserDaoImpl
package com.it.dao.impl;
import com.it.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void findUserByUser() {
System.out.println("查询用户信息");
}
}
UserService
package com.it.service;
public interface UserService {
public void login();
}
UserServiceImpl
package com.it.service.impl;
import com.it.dao.UserDao;
import com.it.dao.impl.UserDaoImpl;
import com.it.service.UserService;
public class UserServiceImpl implements UserService {
private String username;
private Integer age;
private String game;
private UserDao userDao;
public UserServiceImpl(String username, Integer age, String game, UserDao userDao) {
this.username = username;
this.age = age;
this.game = game;
this.userDao = userDao;
}
public UserServiceImpl() {
}
@Override
public void login() {
userDao.findUserByUser();
}
}
Test
package com.it.test;
import com.it.service.UserService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class SpringTest {
//这是一个servlet
public static void main(String[] args) {
//调用service
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = (UserService)ac.getBean("userService3");
userService.login();
}
}
applicationContext.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.it.service.impl.UserServiceImpl">
<!--
给哪个属性赋什么值
确定属性
name: 通过属性名确定属性
type: 通过属性的类型确定属性
index: 通过索引来确定属性
赋值:
value:基本类型的赋值
ref: 引用型类型的赋值
-->
<constructor-arg name="age" value="23" ></constructor-arg>
<constructor-arg name="game" value="LOL"></constructor-arg>
<constructor-arg name="username" value="张三"></constructor-arg>
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
<!-- 有参构造方式-->
<bean id="userService2" class="com.it.service.impl.UserServiceImpl">
<constructor-arg index="1" value="23" ></constructor-arg>
<constructor-arg index="2" value="LOL"></constructor-arg>
<constructor-arg index="0" value="张四"></constructor-arg>
<constructor-arg index="3" ref="userDao"></constructor-arg>
</bean>
<!-- 有参构造方式-->
<bean id="userService3" class="com.it.service.impl.UserServiceImpl">
<constructor-arg type="java.lang.Integer" value="23" ></constructor-arg>
<constructor-arg type="java.lang.String" value="王五"></constructor-arg>
<constructor-arg type="java.lang.String" value="LOL"></constructor-arg>
<constructor-arg type="com.it.dao.UserDao" ref="userDao"></constructor-arg>
</bean>
<bean id="userDao" class="com.it.dao.impl.UserDaoImpl"></bean>
</beans>
2.2.5.2 set方法
UserServiceImpl
package com.it.service.impl;
import com.it.dao.UserDao;
import com.it.dao.impl.UserDaoImpl;
import com.it.service.UserService;
public class UserServiceImpl implements UserService {
private String username;
private Integer age;
private String game;
private UserDao userDao;
public UserServiceImpl(String username, Integer age, String game, UserDao userDao) {
this.username = username;
this.age = age;
this.game = game;
this.userDao = userDao;
}
public void setUsername(String username) {
this.username = username;
}
public void setAge(Integer age) {
this.age = age;
}
public void setGame(String game) {
this.game = game;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public UserServiceImpl() {
}
@Override
public void login() {
userDao.findUserByUser();
}
}
applicationContext.xml
<!-- 属性的set方法 -->
<bean id="userService4" class="com.it.service.impl.UserServiceImpl">
<!--
name:用来确定属性的。
name属性的值是set的方法名去掉set后的驼峰命名名字。
value:基本类型的属性赋值
ref:引用型类型的属性赋值
-->
<property name="username" value="赵六"></property>
<property name="age" value="25"></property>
<property name="game" value="王者荣耀"></property>
<property name="userDao" ref="userDao"></property>
</bean>
2.2.5.3 依赖注入的简写方式(了解)
c名称空间(原理采用的是有参构造)
xmlns:c="http://www.springframework.org/schema/c"
p名称空间 (原理采用的是set方法)
xmlns:p="http://www.springframework.org/schema/p"
<!-- c名称空间-->
<bean id="userService5" class="com.it.service.impl.UserServiceImpl"
c:age="18" c:game="王者荣耀" c:username="c罗" c:userDao-ref="userDao"></bean>
<!-- p名称空间-->
<bean id="userService6" class="com.it.service.impl.UserServiceImpl"
p:age="18" p:username="柳岩" p:game="足球" p:userDao-ref="userDao"></bean>
2.2.5.4 复杂类型的注入
UserServiceImpl2
package com.it.service.impl;
import com.it.dao.UserDao;
import com.it.service.UserService;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.Map;
public class UserServiceImpl2 implements UserService {
private String[] gameNames;
private List<String> dogType;
private Set<String> catType;
private Map<String,String> map;
public void setGameNames(String[] gameNames) {
this.gameNames = gameNames;
}
public void setDogType(List<String> dogType) {
this.dogType = dogType;
}
public void setCatType(Set<String> catType) {
this.catType = catType;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
@Override
public void login(){
}
}
applicationContext.xml
<!--复杂类型的注入-->
<bean id="userService7" class="com.it.service.impl.UserServiceImpl2">
<property name="gameNames">
<array>
<value>LOL</value>
<value>打豆豆</value>
<value>王者荣耀</value>
</array>
</property>
<property name="dogType">
<list>
<value>泰日天</value>
<value>二哈</value>
<value>中华田园犬</value>
</list>
</property>
<property name="catType">
<set>
<value>蓝猫</value>
<value>橘猫</value>
<value>加菲猫</value>
</set>
</property>
<property name="map">
<map>
<entry value="bb" key="aa"></entry>
</map>
</property>
</bean>
3.总结
理解了解
1.工厂模式,理解,关键单例工厂和多例工厂的区别,就是在于单例工厂有一个map集合保存bean对象,
多例没有,创建之后直接返回。
2.spring的工厂类
单例模式下,创建对象的时间节点不一样。
BeanFactory: 顶层接口,什么时候用,什么时候创建对象。
ApplicationContext:BeanFactory的子接口。工厂初始化时创建
掌握的
1.spring的2大核心思想
ioc: 控制反转,对象的创建由我们自己new,换成spring工厂创建
aop: 面向切面的编程,底层就是动态代理,在不修改源码的情况下增强功能
2.spring的入门步骤
a.引入spring-context依赖
b.编写spring的配置applicationContext.xml
c.通过spring工厂获取对象 ApplicationContext(ClasspathXmlApplicationContext)
3.spring的bean标签
id:唯一标识
class:实现类的路径
init-method:初始化要调用的方法
destroy-method:销毁时要调用的方法
scope:
singleton:单例
prototype:多例
4.spring创建对象的3种方式
1.默认无参构造
2.工厂类的静态方法
3.工厂类的动态方法
5.spring的依赖注入
spring在创建对象的时候,给对象的属性赋值,叫做依赖注入。
1.有参构造
<constructor-arg>
确定属性的
name:属性名确定属性
index:索引确定属性
type:类型确定属性
确定值的
value:基本类型赋值
ref:引用类型的赋值
2.set方式
<property>
name:用来确定属性的。
name属性的值是set的方法名去掉set后的驼峰命名名字。
value:基本类型的属性赋值
ref:引用型类型的属性赋值
例工厂的区别,就是在于单例工厂有一个map集合保存bean对象,
多例没有,创建之后直接返回。
2.spring的工厂类
单例模式下,创建对象的时间节点不一样。
BeanFactory: 顶层接口,什么时候用,什么时候创建对象。
ApplicationContext:BeanFactory的子接口。工厂初始化时创建
掌握的
1.spring的2大核心思想
ioc: 控制反转,对象的创建由我们自己new,换成spring工厂创建
aop: 面向切面的编程,底层就是动态代理,在不修改源码的情况下增强功能
2.spring的入门步骤
a.引入spring-context依赖
b.编写spring的配置applicationContext.xml
c.通过spring工厂获取对象 ApplicationContext(ClasspathXmlApplicationContext)
3.spring的bean标签
id:唯一标识
class:实现类的路径
init-method:初始化要调用的方法
destroy-method:销毁时要调用的方法
scope:
singleton:单例
prototype:多例
4.spring创建对象的3种方式
1.默认无参构造
2.工厂类的静态方法
3.工厂类的动态方法
5.spring的依赖注入
spring在创建对象的时候,给对象的属性赋值,叫做依赖注入。
1.有参构造
确定属性的
name:属性名确定属性
index:索引确定属性
type:类型确定属性
确定值的
value:基本类型赋值
ref:引用类型的赋值
2.set方式
name:用来确定属性的。
name属性的值是set的方法名去掉set后的驼峰命名名字。
value:基本类型的属性赋值
ref:引用型类型的属性赋值