Spring基础学习(一) -- IOC, DI, Bean


Spring成员

狂神说Spring

Spring是一个轻量级控制反转(IoC)面向切面(AOP)容器框架.
支持事务的处理, 对框架整合的支持
解决企业应用开发的复杂性, 使现有的技术更容易使用.

SSH: Struct2 + Spring + Hibernate 旧
SSM: SpringMVC + Spring + Mybatis 新

Spring七大组件
在这里插入图片描述

Spring Framework

在这里插入图片描述
在每一层都可以有自己的选择, 都会提供支持

Spring Boot

一个快速开发的脚手架; 可以快速开发一个微服务; 约定大于配置
把很多实践都放到了框架里面, 可以开箱即用
不用生成代码, 没有xml配置

Spring Cloud

基于Spring Boot实现
在这里插入图片描述
把最佳实践固化到系统实践中


IOC

狂神说-Spring IOC
原来的业务分层:

  1. UserDao Dao层
  2. UserDaoImpl 实现类
  3. UserService 业务接口
  4. UserServiceImpl 业务实现类

public class UserServiceImpl implements UserService{
	// 主动创建对象
	private UserDao userDao = new UserDaoImpl();	// 需要根据需求主动更改new UserDaoMysqlImpl
													// new UserDaoOracleImpl等等等

	// 需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set
	// 不去自己new,将主动权从业务层交给用户
	public void setUserDao(UserDao userDao){
		this.userDao = userDao;
	}

	public void getUserDao(){
		userDao.getUser;
	}
}

使用

public class MyTest{
	public static void main(String[] args){
		// 用户实际接触的是业务层, dao层不需要接触
		UserService userService = new UserServiceImpl();	// 主动创建

		(UserServiceImpl userService).setUserDao(new UserDaoSqlImpl);	// 被动调用
	}
}

用户的需求可能会影响原来的代码, 修改一次的成本十分昂贵

从主动的创建对象 --> 被动的接受对象: 控制反转
程序员不需要管理对象的创建, 系统的耦合性大大降低


控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法
没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制;
控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

JavaBean 是一种JAVA语言写成的可重用组件。为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,set和get方法获取。众所周知,属性名称符合这种模式,其他Java 类可以通过自省机制(反射机制)发现和操作这些JavaBean 的属性。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

对象的具体注入从代码中被移除, 取而代之在xml文件中定义.


Hello Spring - IOC实现

Hello实体类 Hello.java

public class Hello {
    private String name;
    public String getName() {
        return name;
    }
    // set方法进行注入
    public void setName(String name) {
        this.name = name;
    }
    public void show(){
        System.out.println("Hello,"+ name );
    }
}

applicationContext.xml Spring的配置文件. Maven下是pom.xml
POM

什么是pom?
POM是项目对象模型(Project Object Model). 该文件用于管理:源代码、配置文件、开发者的信息和角色、问题追踪系统、组织信息、项目授权、项目的url、项目的依赖关系等等。
https://pocnblogs.com/wkrbky/p/6353285.html

包含元素:

  • maven的协作相关属性: groupdId:artifactId:version的形式来唯一确定一个项目
  • POM之间的关系: 继承(parent)、聚合(packaging, modules)与依赖(dependencies)
  • 属性: ${propertyName}的形式引用属性

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">
 java:
 Hello hello = new Hello();
 --> Spring
 id: 变量名; class: new的对象; property: 对象的属性设置
 
    <!--bean就是java对象 ,Spring创建和管理-->
    <bean id="hello" class="com.kuang.pojo.Hello">
        <property name="name" value="Spring"/>
    </bean>
</beans>

测试使用myTest.java

@Test
public void test(){
    //解析beans.xml文件 , 生成管理相应的Bean对象
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml ");
    //getBean : 参数即为spring配置文件中bean的id .
    Hello hello = (Hello) context.getBean("hello");
    hello.show();
}

对象的创建和属性控制都是交给Sping控制
这个过程就叫控制反转 :

  • 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
  • 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .

依赖注入 : 就是利用set方法来进行注入的.
IOC思想 – 由主动的编程, 变成被动的接收

<?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="MysqlImpl" class="com.kuang.dao.impl.UserDaoMySqlImpl"/>
    <bean id="OracleImpl" class="com.kuang.dao.impl.UserDaoOracleImpl"/>
    <bean id="ServiceImpl" class="com.kuang.service.impl.UserServiceImpl">
        <!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写-->
        <!--引用另外一个bean , 不是用value 而是用 ref-->
        <property name="userDao" ref="OracleImpl"/>
    </bean>
@Test
public void test2(){
	// 拿到Spring容器
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    // 需要什么,直接get
    UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");	// 对象已经被创建
    serviceImpl.getUser();
}

要实现不同的操作 , 只需要在xml配置文件中进行修改 , 所谓的IoC,一句话搞定 : 对象由Spring 来创建 , 管理 , 装配 !


依赖注入(DI)

狂神说Spring03:依赖注入(DI)

Set注入

要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .
address.java

 public class Address {
 
     private String address;
 
     public String getAddress() {
         return address;
     }
 
     public void setAddress(String address) {
         this.address = address;
     }
 }

student.java

 package com.kuang.pojo;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
 public class Student {
 
     private String name;
     private Address address;
     private String[] books;
     private List<String> hobbys;
     private Map<String,String> card;
     private Set<String> games;
     private String wife;
     private Properties info;
 
     public void setName(String name) {
         this.name = name;
     }
 
     ...... set for all ......
 
     public void show(){
         System.out.println("name="+ name + ",address="+ address.getAddress() + ",books=");
         for (String book:books){
             System.out.print("<<"+book+">>\t");
         }
         System.out.println("\n爱好:"+hobbys);
         System.out.println("card:"+card);
         System.out.println("games:"+games);
         System.out.println("wife:"+wife);
         System.out.println("info:"+info);
     }
 }
  • 常量注入
 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="小明"/>
 </bean>
  • Bean注入
 <bean id="addr" class="com.kuang.pojo.Address">
     <property name="address" value="重庆"/>
 </bean>
 
 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="小明"/>
     <property name="address" ref="addr"/>
 </bean>
  • 数组注入
 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="小明"/>
     <property name="address" ref="addr"/>
     <property name="books">
         <array>
             <value>西游记</value>
             <value>红楼梦</value>
             <value>水浒传</value>
         </array>
     </property>
 </bean>
  • List注入
 <property name="hobbys">
     <list>
         <value>听歌</value>
         <value>看电影</value>
         <value>爬山</value>
     </list>
 </property>
  • Map注入
 <property name="card">
     <map>
         <entry key="中国邮政" value="456456456465456"/>
         <entry key="建设" value="1456682255511"/>
     </map>
 </property>
  • Set注入
 <property name="games">
     <set>
         <value>LOL</value>
         <value>BOB</value>
         <value>COC</value>
     </set>
 </property>
  • Null值注入
 <property name="wife"><null/></property>
 <property name-"wife" value=""/>	// 空字符串
  • Properties注入
 <property name="info">
     <props>
         <prop key="学号">20190604</prop>
         <prop key="性别"></prop>
         <prop key="姓名">小明</prop>
     </props>
 </property>

P namespace注入和C namespace注入

在配置文件中引入p,c 命名空间

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	<!--第三方约束-->
	   xmlns:p="http://www.springframework.org/schema/p"
	   xmlns:c="http://www.springframework.org/schema/c"
	   
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
 		
 		 <!--P(属性: properties)命名空间 , 属性依然要设置set方法-->
    	 <bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>
    	  <!--C(构造: Constructor)命名空间 , 需要有有参数构造器, 构造器注入, 属性依然要设置set方法-->
		 <bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>

    </bean>

Bean的作用域

https://blog.csdn.net/kongmin_123/article/details/82048392

在这里插入图片描述

  • singleton
    如果bean的作用域的属性被声明为singleton,那么Spring Ioc容器只会创建一个共享的bean实例。对于所有的bean请求,只要id与该bean定义的相匹配,那么Spring在每次需要时都返回同一个bean实例
    Spring的默认模式
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="singleton">
    <!-- collaborators and configuration for this bean go here -->
</bean>
  • prototype
    当一个bean的作用域为prototype,表示一个bean定义对应多个对象实例。声明为prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。

以下scope只会在web中应用

  • request
<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>

Spring容器会在每次用到loginAction来处理每个HTTP请求的时候都会创建一个新的LoginAction实例。
当http请求调用作用域为request的bean的时候,每增加一个HTTP请求,Spring就会创建一个新的bean,在请求处理完成之后便及时销毁这个bean。

  • session
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

Spring容器会在每次调用到userPreferences时,在一个单独的HTTP会话周期来创建一个新的UserPreferences实例。
Session中所有http请求共享同一个请求的bean实例。Session结束后就销毁bean。

  • application
<bean id="appPreferences" class="com.foo.AppPreferences" scope="application"/>

Spring容器会在整个web应用范围使用到appPreferences的时候创建一个新的AppPreferences的实例。
这种作用域在一些程度上来说和Spring的单例作用域相似,但是也有如下不同之处:

  1. application作用域是每个ServletContext中包含一个,而不是每个SpringApplicationContext之中包含一个(某些应用中可能包含不止一个ApplicationContext)。
  2. application作用域仅仅作为ServletContext的属性可见,单例Bean是ApplicationContext可见。

Bean的自动装配

https://blog.csdn.net/qq_33369905/article/details/105828918?spm=1001.2014.3001.5501

自动装配是使用spring满足bean依赖的一种方法. spring会在应用上下文中为某个bean寻找其依赖的bean。
Spring中bean有三种装配机制,分别是:

  • 在xml中显式配置
  • 在java中显式配置
  • 隐式的bean发现机制和自动装配

注解自动装配比自动装配xml配置更加推荐

XML显式装配

使用注解需要:

  • 导入约束context
  • 配置注解的支持 context:annotation-config/
<?xml version="1.0" encoding="UTF-8"?>
<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:annotation-config/> 

	<bean id="cat" class="com.sss.ddd.cat">
		... 简洁
</beans>

@Autowired

public class people{
	@Autowired
	private Cat cat;

	@Autowired
	@Qualifier(value="dog2222")	
	// 自动装配无法通过一个注解完成的时候,可以指定一个名字Qualifier(value=“xxx”)
	// 来配合Autowired来指定一个唯一的bean对象注入
	private Dog dog;
...
}

@Autowired(required = false)
显式的定义了autowired的required属性为false -- 说明这个对象可以为空

可以不需要set方法!

对比:
@Autowired
@Autowired通过byType的方式实现, 要求这个字段必须存在
@Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配

@Resource相似功能

@Resource(name=“cat22”);

@Resource默认通过byName方式实现, 如果找不到, 按byType实现


注解开发

在spring4之后,想要使用注解形式,必须得要引入aop的包
在这里插入图片描述
在配置文件当中,还得要引入一个context约束

<?xml version="1.0" encoding="UTF-8"?>
<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
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
 
</beans>
  1. bean

User.java

package com.spring.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

// bean
/*变成组件 == <bean id="user" class="com.spring.pojo.User"/>*/
@Component
@Scope("singleton")
public class User {
    public String name = "hanhaha";
    //属性注入
    // 相当于bean - property name="gender" value="male"
    @Value("male")
    public String gender;
}

@Component: 组件, 放在类上, 说明这个类被Spring管理了, 变成bean

  1. 属性如何注入

@Value(“xxxx“)

  • @Value(“${}”)
    获取配置文件application.properties中的属性值
@Value(“${user.userName})		// 写在application.properties中的属性配置
String name;	// name就会被注入为上面的值, 可以直接使用这个值

application-test.yml:

spring:
    profiles: test

user:
    userName: 王立国-test
    sex:age: 18
author:
    name: wlg-test
    height: 174
  • @Value("#{}")
    表示常量值 或者 获取bean中的属性
	@Value("#{1}")
	private int number; //获取数字 1
	
	@Value("#{'Spring Expression Language'}") //获取字符串常量
	private String str;
	
	@Value("#{dataSource.url}") //获取bean的属性
	private String jdbcUrl;
  1. 衍生注解
    @Component有几个衍生注解, web开发中, 会按照MVC三层架构分层
  • dao - @Repository
  • service - @Service
  • controller - @Controller
    这四个注解的功能一样, 都是将某个类注册到Spring中, 装配bean
  1. 作用域
    @Scope(“singleton”)

xml和注解的最佳实现:
xml管理bean; 注解完成属性的注入

java显式装配

用一个xxxxConfig.java文件来代替.xml文件来完成bean的装配. 在spring boot中常见

编写一个实体类,Dog

@Component  //将这个类标注为Spring的一个组件,放到容器中!
public class Dog {
    public String name = "dog";
}

2、新建一个config配置包,编写一个MyConfig配置类

@Configuration  //代表这是一个配置类
@import(“导入其他config”)
public class MyConfig {
 
    @Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
    public Dog dog(){
        return new Dog();
    }
}

3、测试
获取上下文的方式也发生了变化

@Test
public void test2(){
    ApplicationContext applicationContext = 
            new AnnotationConfigApplicationContext(MyConfig.class);
    Dog dog = (Dog) applicationContext.getBean("dog");
    System.out.println(dog.name);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值