文章目录
spring 简介
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。
spring优势
1.loc容器可将对象间的依赖关系交由spring控制。避免编码造就过度耦合。
2.aop功能方便面向切面编程
3.声明式事务控制
4.方便集成框架
5.降低api使用难度
6.源码是经典学习典范
组成
spring pom配置
通过maven导入框架所需要的包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>untitled</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.13.2</junit.version>
<spring.version>5.3.13.RELEASE</spring.version>
<commons-logging.version>1.2</commons-logging.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- 添加Spring依赖的jar包-->
<!--依赖注入包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.13</version>
</dependency>
<!--切片包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.13</version>
</dependency>
<!-- Beans包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.13</version>
</dependency>
<!-- 容器包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.13</version>
</dependency>
<!-- 容器依赖包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.3.13</version>
</dependency>
<!-- 核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.13</version>
</dependency>
<!-- 表达式包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.3.13</version>
</dependency>
<!--spring-framework-bom包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>5.3.13</version>
</dependency>
<!--spring-instrument包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>5.3.13</version>
</dependency>
<!--连接数据库包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.13</version>
</dependency>
<!--Spring消息包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>5.3.13</version>
</dependency>
<!--Spring信息包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>5.3.13</version>
</dependency>
<!--Spring对象映射包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.13</version>
</dependency>
<!--spring-oxm包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>5.3.13</version>
</dependency>
<!--Spring测试包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.13</version>
</dependency>
<!--Spring事物管理包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.13</version>
</dependency>
<!--Spring web项目包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.13</version>
</dependency>
<!--SpringMVC包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.13</version>
</dependency>
<!--spring-websocket包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>5.3.13</version>
</dependency>
<!--Spring 依赖commons-logging包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
IOC
在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建以及外部资源获取(不只是对象包括比如文件等)。
●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象:由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转,依赖对象的获取被反转了。
Spring的IoC的底层实现原理是工厂设计模式+反射+XML配置文件。
IOC具体做什么?
IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。
传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;
有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
IoC对编程实现由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
我们在service层中调用dao层,核心代码如下:
// 接口 实例变量 = new 实现类
这时我们便可发现一个缺点:service层和dao层耦合度太高了,即接口和实现类有耦合(它俩之间的联系过于紧密),一旦切换底层实现类,那么就需要修改源代码,这真的不是一个好的程序设计,好的程序设计应当满足OCP原则(也即开闭原则),即在尽量不修改程序源代码的基础上对程序进行扩展。
UserDao dao = new UserDaoImpl();
dao.add();
这时我们便可发现一个缺点:service层和dao层耦合度太高了,即接口和实现类有耦合(它俩之间的联系过于紧密),一旦切换底层实现类,那么就需要修改源代码,这真的不是一个好的程序设计,好的程序设计应当满足OCP原则(也即开闭原则),即在尽量不修改程序源代码的基础上对程序进行扩展。
如若这样做,会发现又产生了一个缺点:现在接口和实现类之间是没有耦合了,但是service层和工厂类耦合了。如果真正想实现程序之间的解耦合,那么就需要使用到工厂设计模式+反射+XML配置文件了。所以,我们这里提供一个XML配置文件,并且该配置文件中有如下配置信息。——————-降低耦合度
<bean id="userDao" class="com.meimeixia.dao.impl.UserDaoImpl" />
理解:例如controller有个属性是service,如果service是接口,那么需要new service的实现类,这样controller和service实现类发生耦合了。但使用IOC后,可以将属性service上面加个@AutoWired,容器的service实现类对象会注入给属性,代码上两者就没关联了,这样就减少了耦合,利于代码开发。
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">
</beans>
然后再来创建一个工厂类,在工厂类中提供一个返回实现类对象的方法,但并不是直接new实现类,而是使用SAX解析配置文件,根据标签bean中的id属性值得到对应的class属性值,使用反射创建实现类对象。——————工厂模式,反射
public class BeanFactory {
public static Object getBean(String id) {
// 1.使用SAX解析得到配置文件内容
// 直接根据id值userDao得到class属性值
String classvalue = "class属性值";
// 2.使用反射得到对象
Class clazz = Class.forName(classvalue);
UserDaoImpl userDaoImpl = (UserDaoImpl)lazz.newInstance();
return userDaoImpl;
}
}
以上就是Spring的IoC的底层实现原理。
IOC接口
1.ioc思想基于IOC容器完成,IOC容器底层就是对象工厂。
2.spring提供IOC容器实现两种方式:(两个接口)
(1)BeanFactory:IOC容器基本实现,内部接口(底层)
加载配置文件不会创建对象,使用时才创建
(2)ApplicationContext:BeanFactory的子接口,提供更多功能,开发人员使用
加载配置文件会创建对象
3.ApplicationContext有实现类
FileSystemXmlApplicationContext ClassPathXmlApplicationContext
DI(依赖注入)------实现IOC
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。
IOC Bean管理------IOC的操作
什么是bean管理
(1)Spring 创建对象
(2)Spring 注入属性(给类的属性赋值)
bean管理操作的两种方式
(1)基于xml
基于xml方式创建对象
<bean id="user" class="com.meimeixia.dao.impl.UserDaoImpl" />
id属性:唯一标识
class:类路径
默认创建的对象无参
基于xml方式注入属性
传统方式
people.setname("张三");
bean
<bean id="user" class="com.meimeixia.dao.impl.UserDaoImpl" />
<property name="name" value="gz"></property>
<property name="id" value="0"></property>
</bean>
基于xml方式创建有参构造器
<bean id="user" class="com.gz.pojo.User">
<constructor-arg name="name" value="gz"></constructor-arg>
<constructor-arg name="id" value="0"></constructor-arg>
</bean>
test
public static void main(String []args)
{
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean1.xml");
User user=applicationContext.getBean("user",User.class);
user.print();
}
IOC底层分析
第一步:加载配置文件
//加载applicationContext.xml
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
ApplicationContext在加载配置时创建对象和属性的注入,在工厂中通过反射创建对象
BeanFactory使用时才创建,在getBean调用时将对象创建和属性注入
public class BeanFactory {
public static Object getBean(String id) {
// 1.使用SAX解析得到配置文件内容
// 直接根据id值userDao得到class属性值
String classvalue = "class属性值";
// 2.使用反射得到对象
Class clazz = Class.forName(classvalue);
UserDaoImpl userDaoImpl = (UserDaoImpl)lazz.newInstance();
return userDaoImpl;
}
}
核心是反射的使用
第二步通过getBean完成赋值
Manger manger=(Manger) context.getBean("manger");
xml自动装配(一般用注解)
(1)根据指定装配规则,Spring自动匹配的属性进行注入
根据属性名字自动装配
根据属性类型自动装配
package com.shw;
public class Manger {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
<bean id="user" class="com.shw.User">
<property name="name" >
<value>小强</value>
</property>
<property name="age" >
<value>25</value>
</property>
<property name="sex" >
<value>男</value>
</property>
</bean>
<bean autowire="byName" id="manger" class="com.shw.Manger"></bean>
manager属性user变量名匹配到上面bean的id,完成自动的属性注入
而类型自动装配,如果manager中有两个user对象(user,user2)的话则会出错
public static void main(String[] args) {
//加载applicationContext.xml
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//获取实例
Manger manger=(Manger) context.getBean("manger");
//调用方法
System.out.println("姓名:"+manger.getUser().getName());
System.out.println("年龄:"+manger.getUser().getAge());
System.out.println("性别:"+manger.getUser().getSex());
}
外部属性文件
把外部属性文件(properties)属性文件引入到spring配置文件中
<context:property-app location="classpath:jdbc.properties">
(2)基于注解
什么是注解
(1)注解是代码的特殊格式,格式:@注解(属性名称=属性名,属性名称=属性值)
(2)使用注解,注解作用在类上面,属性上面
(3)使用注解的目的,简化xml配置
bean管理创建对象使用注解
完整的bean.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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
(1)@Component
(2)@Service
(3)@Controller
(4)@Repository
上面的功能是一样的,都可以创建bean实例,为了开发时更清晰所以有所区分
第一步 引入依赖spring-aop
第二步 开启组件扫描
<context:component-scan base-package="practice01">
</context:component-scan>
扫描包中所有注解
也可以只扫描某种注解
<context:component-scan base-package="practice01" use-default-filters="false">
<context:include-filters type="annotation"
expression="org.springframework.stereotype.Controller"
</context:component-scan>
只扫描@Controller
<context:component-scan base-package="practice01" use-default-filters="false">
<context:include-filters type="annotation"
expression="org.springframework.stereotype.Controller"
</context:component-scan>
不扫描@Controller
第三步 加注解
@Component(value="user") //等效于xml文件中的<bean id="user" class="" />
public class UserImpl implements User{
public void print()
{
System.out.println("开始");
}
}
(value=“user”) 等效于<bean id=“user”…>class就是下方的类
value默认为类名的首字母小写,如UserImpl的默认bean id为userImpl
bean注解注入属性
被使用的bean对象所在的实现类要创建好set方法
(1)@Autowired 根据属性类型进行自动装配-----------将bean中的对象按类型赋给另一个类的属性
可以放在属性和set方法前
-
例如存在一个接口
TestInterface
,有两个实现类分别是TestClass1
和TestClass2
都在spring容器中,此时有一个SomeClass
类需要注入一个TestInterface
属性,代码如下:@Component @Slf4j public class SomeClass { @Autowired //这种方式会报错,因为存在两个TestInterface类型的bean private TestInterface testInterface; //不会报错,因为此时相当于 /* @Autowired @Qualifier("testClass1") */ @Autowired private TestInterface testClass1; public TestInterface getTestClass() { return testClass1; }
(2)@Qualifier 根据属性名称进行注入
要和@Autowired一起使用 用类型和名称找到bean实现类
(3)@Resource 可以根据类型注入,可以根据名称注入
@Resource根据类型注入
@Resource(name="")
(4)@Value:注入普通数据类型的属性
@Value(value=“abc”)
private String name;
配置类
注解的配置文件->配置类config
@Configuration
@ComponentScan(basePackages={"com.atguigu"})
将容器对象类型从xml换成配置类的
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean1.xml");
改为
ApplicationContext applicationContext=new AnnotationConfigApplicationContext(配置类名.class);
bean作用域:
如两次创建的对象
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean1.xml");
User user=applicationContext.getBean("user",User.class);
User user2=applicationContext.getBean("user",User.class);
user和user2指向同一个对象
所以返回的bean对象(配置文件创建的对象)默认为单实例
<bean id="user" class="com.meimeixia.dao.impl.UserDaoImpl" scope=""/>
scope设置单实例/多实例
singleton:单实例,默认
prototype:多实例
IOC用ApplicationContext创建容器时,默认(单实例)会在加载配置文件时会创建对象,多实例不会在加载配置文件时创建对象。
bean生命周期
从对象创建到销毁的过程
(1)通过构造器创建bean实例
(2)为bean属性设置值,(调用set方法)
(3)把bean实例传给BeanPostProcessor(后置处理器)
(4)调用bean的初始化方法,需要配置初始化方法
(5)bean可以使用(对象实例可获取)
(6)把bean实例传给BeanPostProcessor
(7)销毁对象,调用销毁方法,需要配置