什么是spring
spring就是一个管理事务的框架,核心是ioc和aop,不要想象的太复杂,就相当于什么是加法,加法就是用来计算的,核心是数字跟符号。
什么是IOC,IOC有什么作用
IOC又叫控制反转,控制反转(bean标签)的意思就是,生成实例化对象的控制权力反转了,就是生成实例化对象控制的权力发生了变化。以前是直接主动实例化对象,现在是把主动权力给工厂(spring),只能被动的接收。一句话就是,把生成实例化对象的权力给框架或者工厂(spring)。
了解IOC的实现原理才能知道IOC是干嘛的,首先我们介绍工厂模式:工厂模式就是用来生产实例化对象的,为了减少类与类之间的耦合度。
举例:工厂模式的创建对象可以分为单例模式和多例模式,单例模式一般是把所有对象创建在map集合里,用static代码块包裹起来,当加载xml或者properties文件时,在创建工厂时,同时也会创建所有对象。多例模式是指,加载xml方法或者properties方法时,只创建工厂,ID申请一个对象则创建一个对象
**工厂模式简单实现代码:
package com.zxh.bean;
/*
* 第一步:创建properties文件,key=value形式
* 第二步:获取流对象和加载properties文件
* 第三步:使用properties中的key 获取value
* 第四步,使用类加载器,生成对应的对象,返回对象
* */
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
//当类被调用时,Static方法就会直接执行。
public class BeanFactory {
private static Properties proper;
//创建map,当作存放对象的容器。
private static Map<String,Object> beans;
static {
proper = new Properties();
//使用类加载器,获取一个resource的流对象。
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
try {
//获取properties文件
proper.load(in);
//实例化容器对象
beans= new HashMap<String,Object>();
//获取properties中全部的key
Enumeration keys = proper.keys();
//遍历所有的key
while(keys.hasMoreElements())
{
//获取每一个key
String key = keys.nextElement().toString();
//根据key获取value
String beanpath = proper.getProperty(key);
//创建value对象
Object value = Class.forName(beanpath).newInstance();
//把key和value对象存入容器。
beans.put(key,value);
}
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// //根据Bean的名称获取Bean对象(key=value)就是获取可重用组件
//此方式是,调用一次方法,创建一个对象。多例
// public static Object getBean(String beanName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// Object bean =null;
// String beanpath = proper.getProperty(beanName);//获取可重用组件的value,也就是全限定类名。
// bean = Class.forName(beanpath).newInstance();//生成beanpath的对象。
// return bean;
// }
//此方式是,先把全部的对象都先创建好放在beans容器中,然后通过key的值来取对象。 单例模式
public static Object getBean(String beanName) {
return beans.get(beanName);
}
}
工厂模式创建的工厂就相当于IOC容器,就是用来创建对象的,具体流程就是:给我一个id字段 ——工厂生产对象——返回生产的对象。把类与类之间的关系变成了类——工厂——类的关系,实现了编译解耦。
思路:
第一步:不使用new 使用反射。 第二步:通过配置文件,引用配置文件(xml或者properties)。 采用工厂模式。 一个创建Bean对象的工厂 首先创建一个配置文件(key=value),然后再配置文件中写好配置的内容,然后引用配置文件反射到工厂中产生对象。
Bean是可复用的组件,比如JavaBean
但是Bean> JavaBean
JavaBean是指用JAVA语言写的可重用组件,比如实体类。
但是JavaBean>实体类POJO
IOC容器的使用也跟工厂模式差不多
获取spring的IOC容器
1.ApplicationContext构建IOC容器,创建对象的方式采用立即加载,读取完XML后,就已经存在了所有对象,单例对象。
2.BeanFactory构建IOC容器,创建对象采用延迟加载,来一个id(key),生产一个对象(value ),多例对象。
IOC容器是一个map集合,存储的是工厂中产生的对象。
根据ID获取对象
拿到IOC容器
ApplicationContext 有三个常用实现类
ClassPathxmlApplicationContext 加载类路径下的配置文件,要求配置文件必须在类路径下才能加载
FilesysytemxmlApplicationContext 加载磁盘任意位置下的配置文件,必须要有访问权限。
AnnotationConfigAoolicationContext 读取注解创建容器
具体代码
package com.zxh.servlet;
import com.zxh.factory.BeanFactory;
import com.zxh.service.SaveacountService;
import javafx.application.Application;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Test {
/*
* 一.获取spring的IOC容器
* 1.ApplicationContext构建IOC容器,创建对象的方式采用立即加载,读取完XML后,就已经存在了所有对象,单例对象。
* 2.BeanFactory构建IOC容器,创建对象采用延迟加载,来一个id(key),生产一个对象(value ),多例对象。
* IOC容器是一个map集合,存储的是工厂中产生的对象。
* 二.根据ID获取对象
* */
public static void main(String[] args){
//拿到IOC容器
/*ApplicationContext 有三个常用实现类
* ClassPathxmlApplicationContext 加载类路径下的配置文件,要求配置文件必须在类路径下才能加载
* FilesysytemxmlApplicationContext 加载磁盘任意位置下的配置文件,必须要有访问权限。
* AnnotationConfigAoolicationContext 读取注解创建容器
* */
// ApplicationContext as = new FileSystemXmlApplicationContext("D:\\intelij\\springframework\\springfirst\\src\\main\\resources\\bean.xml");
ApplicationContext as = new ClassPathXmlApplicationContext("bean.xml");
//获取对象
SaveacountService ss = (SaveacountService) as.getBean("AccountService");
SaveacountService ss1 = (SaveacountService) as.getBean("AccountService");
ss.Saveaccount();
System.out.println(ss);
System.out.println(ss1);
}
}
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">
<!-- 把对象创建的控制权交给 spring来管理 -->
<!-- 键值对新式-->
<!-- Spirng对Bean的3个管理方面
一.创建Bean对象的3种方式
1.使用默认构造函数创建,首先在spring中配置bean标签(可以有多个bean标签),其次属性只有id和class,没有其他的属性和标签
且类的默认构造方法存在,不然无法使用。
<bean id="AccountService" class="com.zxh.serviceimpl.SaveaccountServiceimpl"></bean>
<bean id="AccountDao" class="com.zxh.daoimpl.SaveacountDaoimpl"></bean>
2.使用工厂中(某一个类中)的方法创建对象,存入spring容器。首先获取工厂对象,然后调用工厂对象的方法。
<bean id="BeanFactory" class="com.zxh.factory.BeanFactory"></bean>
<bean id="AccountService" factory-bean="BeanFactory" factory-method="getBean"></bean>
3.使用工厂中(某个类中)的静态方法创建对象,存入spring容器
这一步根本没有创建工厂对象,直接调用static方法。
<bean id="AccountService" class="com.zxh.factory.BeanFactory" factory-method="getBeanone"></bean>
二.bean对象的作用范围
属性标签:scope
取值:singleton 单例(默认值)
prototype 多例模式
request 作用于Web应用的请求范围(请求转发,二次请求不可用)
session 作用于Web应用的会话范围(重定向,同一个用户的不同请求可用)
global-session(跨服务器) 作于于集群环境的会话范围(全局会话范围),不是集群中跟session一样。
三.bean对象的生命周期
单例对象(看容器得状态)
出生:IOC容器创建时对象出生
存在:容器在则一直存在
销毁:容器销毁则销毁 destroy-method=""标签。
多例对象(spring框架)
出生:spring框架创建
存在:只要使用就一直活着
销毁:长时间不使用或者不被引用,则会被垃圾回收器自动回收
-->
```c
在这里插入代码片
以下是spring的依赖注入标签使用
<!-- spring依赖注入
什么是依赖关系
就是创建对象的需要用到的其他类。
什么是依赖注入
就是把类与类之间的关系转移给spring,类只与spring进行交互。
依赖关系的管理:
统一交给交给spring创建,管理和维护,我们只需要在xml中说明。
注入的数据:
1.基本类型
2.bean类型(在xml中或者注解中配置过的类型)
3.集合类型
注入的方式:
1.使用构造函数
2.使用set方法
3.使用注解提供
-->
<!-- 构造函数注入
使用标签:constructor-age
位置:bean内部
属性:(key -value)
type:指定注入数据类型(int ,string,char),该数据类型是构造函数中的某些数据类型。(一般不用)
index:把数据注入到构造函数中相应的索引位置中。(也不要)
name:把数据注入到构造函数中指定的属性名称中(用这个)
value:需要注入的数据内容。提供基本类型和string
ref:需要注入的bean对象。从IOC中拿取已有的bean对象
缺点:
在使用这个bean对象时,必须要注入数据,不然无法创建bean对象。
<bean id="AccountService" class="com.zxh.serviceimpl.SaveaccountServiceimpl">
<constructor-arg name="name" value="test"></constructor-arg>
<constructor-arg name="password" value="123"></constructor-arg>
</bean>
-->
<!-- set方法注入 依赖注入一般用此方法,能无参注入,也能有参注入.
使用标签:property
位置:bean内部
属性:(key - value)
name:指定的是注入时候的方法名。比如setName,只需要写成name="name"
value:需要注入的数据内容。提供基本类型和string
ref:需要注入的bean对象。从IOC中拿取已有的bean对象
<bean id="AccountService" class="com.zxh.serviceimpl.SaveaccountServiceimpl">
<property name="name" value="张贤浩"></property>
<property name="password" value="123465"></property>
</bean>
-->
<!-- 集合类型注入
用于list的标签有:list array set
用于map的标签有:map props
所有结构相同的标签可以互换
<bean id="AccountService" class="com.zxh.serviceimpl.SaveaccountServiceimpl">
<property name=""> name是一个返回类型为list的set方法。
<list> 还有arry,map,property
<value></value>
<value></value>
<value></value>
</list>
</property>
</bean>
-->
以下是spring注解开发标签的基本使用
package com.zxh.serviceimpl;
import com.zxh.dao.SaveacountDao;
import com.zxh.service.SaveacountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/*
*
采用xml配置 <bean id="AccountService" class="com.zxh.serviceimpl.SaveaccountServiceimpl"
* scope="" init-method="" destroy-method="">
* <property name="" value="" ref=""></propety>
* </bean>
* 采用注解配置
* 用于创建对象的注解
* 和bean标签一样
* @Component
* 作用:把当前对象注入到spring容器中
* 属性:
* value:指定bean对象的id。默认值是 当前类名 改首字母小写
* @Controller------servlet
* @Service -----service
* @Repository -----dao
* 以上三个注解,与Component一模一样
* 是spring提供的三层框架原理,看起来更清晰方便。
* 用于注入数据的注解
* 和bean标签中property一样(set注入)
* @Autowired(不写set方法也可以注入成功!)
* 作用:按照类型自动注入,但需要容器中有唯一一个bean对象类型和要注入的变量类型配备。
* 就是首先需要容器里面有一个对象,且这个对象跟注入的变量类型一样。
* 比如你要注入User类型的对象,则你的容器里要有一个User类型的对象,而且是唯一的
* 位置:可以是变量上,也可以是方法上。
* 细节:假如有多个User类型,首先会把容器中所有的User类型都选择起来,
* 然后根据变量名称去所有User类型中寻找相同的key,如果存在注入成功,不存在报错。
* @Qualifier(不能独立使用,必须跟Autowired配合使用)
* 作用:
* 属性:
* value:用于按照指定注入的id,注意是指定。
@Resource
作用: 直接按照bean的id注入,不提托Autowired
属性:
name:指定bean的ID
——————————基本类型和Stirng类型不能使用以上注解实现,集合类型的注入只能通过xml实现 ——————————————————————
@Value
* 作用:用于注入基本类型和String类型的注入
* 属性:
* value:需要注入的数据,不是id。可以使用spring的spEL表达式 。value="${表达式}"
* * 用于改变作用范围的
* 和bean标签中使用scope属性一样。
* @Scope
* 作用:用于指定作用范围
* 属性:
* value:指定范围的取值,有 singleton prototype session golbel-session
* 用于生命周期的
* 和bean标签中init个destroy一样
* @PreDestory:(spring只负责销毁单例对象,不负责多例。)
* 作用:用于指定销毁方法
* @PostConstruct:
* 作用:用于指定初始化方法
* */
@Component(value="acount")
@Scope(value = "singleton")
public class SaveaccountServiceimpl implements SaveacountService {
@Autowired()
@Qualifier("accountdao")
private SaveacountDao dao;
public void Saveaccount()
{
System.out.println("this is a service");
}
@PostConstruct
public void init()
{
System.out.println("初始化");
}
@PreDestroy
public void destroy()
{
System.out.println("销毁");
}
public void Saveaccountx()
{
dao.saveacount();
}
}
以下是把配置文件换到class中的注解配置
package com.zxh.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
/*
* 该类是一个配置类,作用和spring.xml一样的
* spring中的新注解
* @Configuration
* 作用:指定一个配置类
* @ComponentScan
* 作用:指定spring创建容器时需要扫描的包 等于
* <context:component-scan base-package="com.zxh"></context:component-scan>
* 属性:
* value和basePackages 两个属性作用一样.都是指定需要扫描的包
* @Bean
* 作用:把当前方法的返回值作为bean对象,存入IOC容器 等于
* <bean id="" class="" ></bean>
* 属性: name
* 用于指定Bean的ID,默认是当前方法名
* 细节:当使用此注解去配置方法时,如果方法有参数,会自动去容器中找有没有合适的bean对象.跟Autowired一样.
@Import
* 作用:用于导入其他配置类
* 属性:
* value:用于指定其他配置类的字节码
* 有import标签的时主配置类,导入的都是子配置类
* @PropertySource
* 作用:引入properties文件
* 属性:
* value:用于指定需要引入的文件名称和路径 value="classpath:xxxx/xxx/xxx/.properties"
*
* */
@Configuration
@ComponentScan(value = "com.zxh")
public class configuration {
/*
* guang
* */
@Bean(name = "queryrunner")
public QueryRunner CreateQuery(DataSource datasource)
{
return new QueryRunner(datasource);
}
/*
* 创建数据源对象
*
* */
@Bean(name = "datasource")
public DataSource Createsource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/spring");
ds.setUser("root");
ds.setPassword("root");
return ds;
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
}
总结
学习spring,我们首先要了解spring是用来干嘛的,然后再去了解工厂模式,接着类比工厂模式去理解IOC的的作用和spring的作用,然后学会使用spring xml标签的配置和在类中与IOC容器交互的方法。