Spring (1) IOC

Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。

优点:

1.Spring是一个开源的免费的框架(容器)

2.Spring是一个轻量级的,非入侵式的框架

3.控制反转(IOC)和面向切面编程(AOP)

4.支持事务的处理,对框架整合的支持

模块

Spring Boot:一个快速开发的脚手架,基于SpringBoot可以快速的开发单个微服务(约定大于配置),学习Spring Boot前提是完全掌握Spring及SpringMVC。

Spring Cloud:是基于Spring Boot实现的

弊端:Spring发展太久之后,违背了原来的理念,配置变得十分繁琐。

IOC理论推导

用户实际调用的是业务层,dao层它们不需要接触。在idea中,用idea中的main方法来模拟用户的需求。

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原来的代码!如果代码量非常大,修改一次的成本会很十分昂贵。

之前,程序是主动创建对象的,控制权在程序员手里。

UserDao userDao

public class UserServiceImpl implements UserService{

    UserDao userDao=new UserDaoOracleImpl;
    //UserDao userDao=new UserDaoSqlImpl;

    @Override
    public void getUser() {
        userDao.getUser();
    }
}
public class Test {
    public static void main(String[] args) {

        //main方法代表客户端,模拟的是用户需求,实际调用的是业务层,dao层他们不需要调用
        UserService userService=new UserServiceImpl();
        userService.getUser();
    }
}

 当客户需求发生改变时,需要修改业务层的代码(UserDao userDao是死的)。

使用set注入以后,程序不再具有主动性,而是变成了被动的接收对象

public class UserServiceImpl implements UserService{

    UserDao userDao;

    @Override
    public void getUser() {
        userDao.getUser();
    }

    @Override
    public void setUserDao(UserDao userDao) {
        this.userDao=userDao;
    }
}
public class Test {

    public static void main(String[] args) {

        //main方法代表客户端,模拟的是用户需求,实际调用的是业务层,dao层他们不需要调用
        UserService userService=new UserServiceImpl();
        userService.setUserDao(new UserDaoImpl());
//        不同的UserDao代表者着不同的需求
//        userService.setUserDao(new UserDaoOracleImpl());
//        userService.setUserDao(new UserDaoSqlImpl());
        userService.getUser();
    }
}

 当客户需求发生改变时,不需要修改业务层的代码(UserDao userDao由顾客定)。

这种IOC思想从本质上解决了问题,程序员不用再去管理对象的创建。系统的耦合性(块间联系)大大降低,可以更加专注的在业务上的实现。       

右图为IOC思想                                                                              

 HelloSpring(初识Spring)

1.配置ApplicationContext.xml文件,将对象放入Spring容器中

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

        <!--使用Spring来创建对象,在Spring中都被称为Bean-->
    <bean id="hello" class="com.kuanghui.pojo.Hello">
        <property name="name" value="Spring"/>
    </bean>

</beans>
    <!--使用Spring来创建对象,在Spring中都被称为Bean-->
    <bean id="mysql" class="com.kuanghui.dao.UserDaoSqlImpl"/>
    <bean id="oracle" class="com.kuanghui.dao.UserDaoOracleImpl"/>

    <bean id="service" class="com.kuanghui.service.UserServiceImpl">
        <!--ref:  引用Spring容器中创建好的对象      -->
        <property name="userDao" ref="mysql"/>
    </bean>

 2.通过Spring容器创建对象

public class MyTest {

    public static void main(String[] args) {
        //获取Spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //我们的对象都在Spring中管理了,我们要使用,直接去Spring中取出来就可以了
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());
    }
}

hello对象由Spring创建,hello对象的属性由Spring容器设置

控制:传统的应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring创建的。容器就是Beans标签。

反转:程序本身不创建对象,而变成被动的接收对象

依赖注入:利用set方法来进行注入

所谓的IOC,就是对象由Spring来创建,管理,装配!以后要实现不同的操作,只需要在xml配置文件中进行修改即可,彻底不需要去修改程序中的代码。

IOC创建对象的方式

当程序运行时,即使被注册的bean不使用,它也会被创建。

1.使用无参构造创建对象,默认!

    <bean id="user" class="com.kuanghui.pojo.User">
        <property name="name" value="Shenyycccc"/>
    </bean>

2.假如我们使用有参构造创建对象

    <!--使用Spring来创建对象,在Spring中都被称为Bean-->
    <!--第一种:下标赋值-->
    <bean id="user" class="com.kuanghui.pojo.User">
        <constructor-arg index="0" value="Shenyccc"/>
    </bean>

    <!--第二种:类型赋值,若该有参构造器有两个相同的类型,此方法就不行了
        所以不推荐使用-->
    <bean id="user1" class="com.kuanghui.pojo.User">
        <constructor-arg type="java.lang.String" value="Syc"/>
    </bean>
    
   <!--第三种:直接通过参数名赋值,推荐-->
   <bean id="user2" class="com.kuanghui.pojo.User">
       <constructor-arg name="name" value="SSyc"/>
   </bean>

总结:在配置文件加载时,Spring容器中管理的对象就已经初始化了.

Spring配置

别名

如果我们添加了别名,也可以通过别名获取到这个对象。

    <alias name="user" alias="wok"/>

Bean

id:bean的唯一标识符,相当于Java中的对象名

class:bean对象所对应的全限定名:包名+类型名

name:也是别名,而且name可以同时取多个别名

    <bean id="user" class="com.kuanghui.pojo.User">
        <property name="name" value="Shenyycccc" name="user2,user3,user4"/>
    </bean>

import

这个import一般用于团队开发,它可以将多个配置文件导入合并为一个。

<import resource="beans.xml"/>

DI依赖注入

1.构造器注入

    <!--使用Spring来创建对象,在Spring中都被称为Bean-->
    <!--第一种:下标赋值-->
    <bean id="user" class="com.kuanghui.pojo.User">
        <constructor-arg index="0" value="Shenyccc"/>
    </bean>

    <!--第二种:类型赋值,若该有参构造器有两个相同的类型,此方法就不行了
        所以不推荐使用-->
    <bean id="user1" class="com.kuanghui.pojo.User">
        <constructor-arg type="java.lang.String" value="Syc"/>
    </bean>
    
   <!--第三种:直接通过参数名赋值,推荐-->
   <bean id="user2" class="com.kuanghui.pojo.User">
       <constructor-arg name="name" value="SSyc"/>
   </bean>

2.Set方式注入(依赖)

依赖注入:Set注入

依赖:bean对象的创建依赖于Spring容器

注入:bean对象中的所有属性都由容器来注入

public class Student {
    String name;
    Address address;
    String[] books;
    List<String> hobbys;
    Map<String,String> card;
    Set<String> games;
    String wife;
    Properties properties;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobbys() {
        return hobbys;
    }

    public void setHobbys(List<String> hobbys) {
        this.hobbys = hobbys;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getWife() {
        return wife;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address.getAddress() +
                ", books=" + Arrays.toString(books) +
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", properties=" + properties +
                '}';
    }
}
        <bean id="address" class="com.kuanghui.pojo.Address">
            <property name="address" value="CJLU"/>
        </bean>

        <bean id="student" class="com.kuanghui.pojo.Student">
<!--            普通值注入    -->
            <property name="name" value="Shenyc"/>
<!--            bean注入-->
            <property name="address" ref="address"/>
<!--            数组注入-->
            <property name="books">
                <array>
                    <value>book1</value>
                    <value>book2</value>
                    <value>book3</value>
                </array>
            </property>
<!--            list注入-->
            <property name="hobbys">
                <list>
                    <value>hobby1</value>
                    <value>hobby2</value>
                    <value>hobby3</value>
                </list>
            </property>
<!--            map注入-->
            <property name="card">
                <map>
                    <entry key="card1" value="111"/>
                    <entry key="card2" value="222"/>
                    <entry key="card3" value="333"/>
                </map>
            </property>
<!--            set注入-->
            <property name="games">
                <set>
                    <value>game1</value>
                    <value>game2</value>
                    <value>game3</value>
                </set>
            </property>
<!--            null,等价于<property name="wife" value="">-->
            <property name="wife">
                <null></null>
            </property>
<!--            Properties
                key=value-->
            <property name="properties">
                <props>
                    <prop key="学号">xuehao</prop>
                    <prop key="性别">nan</prop>
                </props>
            </property>
        </bean>

3.拓展

如果想要使用p或者c标签,需要加上下面的语句

       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
    <!--使用p标签注入,可以直接注入属性的值,相当于property-->
    <bean id="user" class="com.kuanghui.pojo.User" p:age="3" p:name="shenyc"/>

    <!--使用p标签注入,通过构造器注入属性的值,相当于construction-args -->
    <bean id="user1" class="com.kuanghui.pojo.User" c:age="1" c:name="shenyc111"/>

注意点:p命名和c命名不能直接使用,需要导入xml约束。

Bean的作用域

Scope说明

singleton

(默认情况下)为每个Spring IoC容器将单个Bean定义的Scope扩大到单个对象实例。

prototype

将单个Bean定义的Scope扩大到任何数量的对象实例。

request

将单个Bean定义的Scope扩大到单个HTTP请求的生命周期。也就是说,每个HTTP请求都有自己的Bean实例,该实例是在单个Bean定义的基础上创建的。只在Web感知的Spring ApplicationContext 的上下文中有效。

session

将单个Bean定义的Scope扩大到一个HTTP Session 的生命周期。只在Web感知的Spring ApplicationContext 的上下文中有效。

application

将单个Bean定义的 Scope 扩大到 ServletContext 的生命周期中。只在Web感知的Spring ApplicationContext 的上下文中有效。

websocket

将单个Bean定义的 Scope 扩大到 WebSocket 的生命周期。仅在具有Web感知的 Spring ApplicationContext 的上下文中有效

1.单例模式(Spring机制默认)

<bean id="user" class="com.kuanghui.pojo.User" p:age="3" p:name="shenyc" 
scope="singleton"/>

2.原型模式(每次从容器中get的时候,都会产生一个新的对象)

<bean id="user" class="com.kuanghui.pojo.User" p:age="3" p:name="shenyc" 
scope="prototype"/>

3.其余的request,session,application这些只能在web开发中使用

Bean的自动装配

自动装配是Spring满足bean依赖的一种方式!

Spring会在上下文中自动寻找,并自动给Bean装配对象

Spring三种装配方式

1.在xml中显示配置

2.在Java中显示配置

3.隐式的自动装配(重要)

ByName和ByType自动装配

    <bean id="cat" class="com.kuanghui.pojo.Cat"/>
    <bean id="dog" class="com.kuanghui.pojo.Dog"/>
    <!--
        byName:会自动在容器上下文中查找,和自己对象属性名对应的beanId
        byType:会自动在容器上下文中查找,和自己对象 属性类型相同的bean
    -->
    <bean id="people" class="com.kuanghui.pojo.People" autowire="byName">
        <property name="name" value="小王"/>
    </bean>
    <bean id="people1" class="com.kuanghui.pojo.People" autowire="byType">
        <property name="name" value="小王"/>
    </bean>


    //等价于
    <bean id="people1" class="com.kuanghui.pojo.People" autowire="byType">
        <property name="name" value="小王"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    </bean>

小结:1.byName的时候,需要确保所有bean的id唯一,并且这个bean需要和自动注入的属性名一致。2.byType的时候,需要确保所有bean的class唯一,并且这个bean需要和自动注入的属性类型一致。

Spring所需的jar包

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>

使用注解开发实现自动装配

jdk1.5开始支持注解,Spring2.5开始支持注解。

要使用注解

1.导入约束

 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"

2.配置注解支持

<context:annotation-config></context:annotation-config>

@Autowired

直接在属性上使用,也可以在set方法上使用

使用Autowired我们可以不用再编写Set方法了,前提是你这个装配的属性在IOC(Spring)容器中。

@Autowired先通过类型装配,如果出现多个类型,再通过beanId装配。

@Qualifier

@Qualifier注解的作用是指定需要注入的Bean的名称,在进行自动装配(如@Autowired)的过程中,指定注入哪一个实例,一般跟@Autowired注解配合使用。@Qualifier注解是通过byName进行自动注入的。当在容器中有多个同类型的bean时,使用@Autowired注解默认会按照byType自动注入,即会自动查找与属性类型匹配的bean,但若这些同类型的bean存在一些差异,我们就可以使用@Qualifier注解指定具体的bean的名称,从而避免自动装配时存在的歧义。

@Nullable

字段标记了这个注解,说明这个字段可以为null。

@Resource(java的注解)

@Resource默认按byName自动注入,也提供按照byType 注入

小结:@Resource和@Autowired区别:@Autowired注解来自于Spring Framework,而@Resource注解来自于J2EE规范。@Autowired注解默认按类型(by type)进行匹配注入,如果类型相同,则按名称(by name)进行匹配注入。而@Resource注解默认按名称(by name)进行匹配注入,如果名称不存在,则按类型(by type)进行匹配注入。

public class People {

    @Autowired
    @Qualifier(value = "dog")
    Dog dog;

    @Resource
    Cat cat;
    String name;

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "People{" +
                "dog=" + dog +
                ", cat=" + cat +
                ", name='" + name + '\'' +
                '}';
    }
}

使用注解开发

在Spring4之后,要使用注解开发,必须保证aop的包导入了。

使用注解需要导入context约束,增加注解的支持。

    <!--指定要扫描的包,这个包下的注解就会生效-->
    <context:component-scan base-package="com.kuanghui.pojo"/>

    <context:annotation-config></context:annotation-config>

Bean注入

@Component

组件,放在类上,说明这个类被Spring管理了

@Component注解通常用于声明一个被Spring容器托管的bean。如果没有为该注解指定bean的名称,则Spring将使用默认的bean名称。默认情况下,bean的名称为类名称的第一个字母小写形式。如果需要为@Component指定一个特定的bean名称,则可以使用value或name属性。

//等价于<bean id="user" class="com.kuanghui.pojo.User"/>
@Component
public class User {
    public String name;
}

属性注入

@Value()

@Component
public class User {

    //相当于<property name="name" value="Shenyyccc"/>
    @Value("Shenyyccc")
    public String name;
}

也可以这样实现 

@Component
public class User {

    public String name;

    //也可以这样实现
    @Value("Shenyyccc")
    public void setName(String name){
        this.name=name;
    }
}

衍生注解

@Component有几个衍生注解,功能都相同,只不过我们在web开发中,会按照mvc三层架构分层!

dao:@Repository

service:@Service

controller:@Controller

注意:这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配。

@Mapper和@respository区别。

1、使用@mapper后,不需要在spring配置中设置扫描地址,通过mapper.xml里面的namespace属性对应相关的mapper类,spring将动态的生成Bean后注入到ServiceImpl中。

2、@repository则需要在Spring中配置扫描包地址,然后生成dao层的bean,之后被注入到ServiceImpl中

作用域

@scope()

@Component
@Scope("singleton")
public class User {

    public String name;

    //也可以这样实现
    @Value("Shenyyccc")
    public void setName(String name){
        this.name=name;
    }

小结

xml和注解:

1.xml更万能,适用于任何场合,维护简单方便

2.注解 维护相对复杂

3.想让注解生效,必须开启注解的支持。

使用Java的方式配置Spring

我们现在要完全不适用Spring的xml配置了,全权交给Java来做!

JavaConfig是Spring的一个子项目。在Spring4之后,它成为了一个核心功能。

@Component
public class User {

    String name;

    public String getName() {
        return name;
    }

    @Value(value = "Shenyc")
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
//@Configuration注解类似于Spring配置文件ApplicationContext中的beans标签
//这个注解也会被Spring托管,注册到容器中,因为他本身就是一个@Component
//@Comfiguration代表一个配置类,就和我们之前看的beans.xml一样
@Configuration
//@ComponentScan("com.kuanghui.pojo")
//相当于<context:component-scan base-package="com.kuanghui.pojo"/>
@ComponentScan("com.kuanghui.pojo")
//相当于导入了另外一个文件配置类
@Import(SpringConfig1.class)
public class SpringConfig {

    //注册一个bean,就相当于我们之前写的一个bean标签,
    // 这个方法的名字,就相当于bean标签的id
    // 这个方法的返回值,就相当于bean标签中的class属性
    @Bean
    public User getUser(){
        return new User();
    }
}
    @Test
    public void test(){
        //如果完全使用了配置类方式去做,我们只能通过AnnotationConfigApplicationContext来获取容器,
        // 通过配置类的clss对象加载
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        User user = context.getBean("getUser", User.class);
        System.out.println(user.getName());
    }

 方法一:@ComponentScan("com.kuanghui.pojo")是和pojo中的类@Component搭配使用的,获取对象时使用的是小写类名,请区别@Bean注解。也需要标明@Configuration。

方法二:@Configuration和@Bean搭配使用,@Configuration注解表示这个类是一个配置类,它标识这个类中定义了Bean的配置方法。被标注为@Configuration的类中的方法通常使用@Bean注解来声明Bean。配置类中的@Bean方法会被Spring容器调用,返回的对象会被注册为Spring容器中的Bean。@Configuration注解可以理解为替代了传统的XML配置文件。

这种纯Java的配置方式,在SpringBoot中随处可见!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值