学习笔记——Spring(一)简介和IOC

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,有两个实现类分别是TestClass1TestClass2都在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)销毁对象,调用销毁方法,需要配置

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值