Spring Learning Note

本文详细介绍了Spring框架的核心特性,包括其作为企业级开发解决方案的角色,SSH和SMM框架组合,以及Spring的优点和缺点。重点讲解了Spring的控制反转(IOC)原理,通过XML和注解实现依赖注入,并探讨了不同类型的DI方式。此外,文章还提到了Spring的bean作用域、自动装配机制、注解开发以及Java配置和代理模式,尤其是静态和动态代理的概念及其在实际开发中的应用。
摘要由CSDN通过智能技术生成

1、Introduction of Spring

 purpose:解决企业级开发的复杂性,整合了现有技术框架

SSH:Struct2+Spring+Hibernate

旧三大框架:SSH
Struts2:主要用于用户通过浏览器与后台程序进行交互。
Spring:主要是将一些主流的框架进行整合,方便程序员进行调用,能够较完美整合其他框架。
Hibernate:主要用于程序与数据库的交互。

SMM: SpringMVC+Spring+Mybatis

Spring 优点

        开源免费框架

        轻量级,非入侵式框架

        控制反转(IOC),面向切面变成(AOP)

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

Spring 缺点

        配置地狱

Spring 7大模块

 

SpringBoot和SpringCloud必须掌握Spring和SpringMvc

Spring Boot

        快速开发脚手架

        可快速开发单个微服务

        约定大于配置 

Spring Cloud 

        基于SpringBoot实现

2、IOC

pom.xml中导入jar包

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

 传统设计:user调用service,service调用dao,主动性在user

IOC:user调用service,service掌握主动权(通过xml),service控制调用dao

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

 对象的属性由Spring容器设置,这个过程称为控制反转

控制:传统的对象是由程序本身控制创建的,使用Spring后,是由Spring来创建的

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

DI:利用set方法来进行注入

IOC是一种编程思想,由主动的编程变为被动的接受 (方法:newClassPathXmlApplicationContext)

总结:对象由Spring创建,管理,配置。

2.1配置IOC metadata

resource folder下新建xml(spring 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" 
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

插入多个bean来注册class,一个bean代表一个class

</beans>

2.2 DI

2.2.1 constructor-based DI

class中记得构造get和set方法

无参构造:默认,直接new。

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationcontext.xml");
        UserServiceImple userServiceImple=(UserServiceImple) context.getBean("userserviceimpl");
        userServiceImple.getUser();;
    }
}

有参构造:

class例:

package x.y;

public class ThingOne {

    public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
        // ...
    }
}
<beans>
    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg ref="beanTwo"/>
        <constructor-arg ref="beanThree"/>
    </bean>

    <bean id="beanTwo" class="x.y.ThingTwo"/>

    <bean id="beanThree" class="x.y.ThingThree"/>
</beans>

1st type DI (不推荐)

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>

2nd index DI

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>

3rd name DI (常用)

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateAnswer" value="42"/>
</bean>

总结:配置文件加载时,容器中管理对象都已经初始化。

2.2.2 setter-based DI

依赖:xml对象的创建依赖于容器

注入:xml对象中的所有属性

实例分析:

Address class

package com.jj;

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

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

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address+ '\'' +
                '}';
    }
}

 Student class

package com.jj;

import java.util.*;

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

    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> getHobby() {
        return hobby;
    }

    public void setHobby(List<String> hobby) {
        this.hobby = hobby;
    }

    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 getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address.toString() +
                ", books=" + Arrays.toString(books) +
                ", hobby=" + hobby +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }
}

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">
    <bean id="address" class="com.jj.Address">
        <property name="address" value="杭州"/>
    </bean>
    <bean id="student" class="com.jj.Student">
<!--        第一种,普通值注入 value-->
        <property name="name" value="zhao"/>
<!--        第二种,bean注入,ref-->
        <property name="address" ref="address"/>
<!--        数值注入-->
        <property name="books">
            <array>
                <value>西游记</value>
                <value>红楼梦</value>
                <value>三国</value>
            </array>
        </property>
<!--        List-->
        <property name="hobby">
            <list>
                <value>吃饭</value>
                <value>睡觉</value>
                <value>打游戏</value>
            </list>
        </property>
<!--        Map-->
        <property name="card">
            <map>
                <entry key="身份证" value="123123123"/>
                <entry key="银行卡" value="2334546677"/>
            </map>
        </property>
<!--        Set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>PUBG</value>
                <value>DNF</value>
            </set>
        </property>
<!--        null-->
        <property name="wife">
            <null/>
        </property>

<!--        properties-->
        <property name="info">
            <props>
                <prop key="No">2021025</prop>
                <prop key="Sex">男</prop>
                <prop key="token">root</prop>
                <prop key="password">1234</prop>
            </props>
        </property>
    </bean>
</beans>

注意:Address方法需构造toString(否则获取的值不是设定的值)

 程序

import com.jj.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.swing.text.AbstractDocument;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student= (Student) context.getBean("student");
        System.out.println(student);

    }
}

结果

Student{name='zhao', address=Address{address='杭州'}, books=[西游记, 红楼梦, 三国], hobby=[吃饭, 睡觉, 打游戏], card={身份证=123123123, 银行卡=2334546677}, games=[LOL, PUBG, DNF], wife='null', info={No=2021025, Sex=男, password=1234, token=root}}

2.2.3 拓展(c/p)

xml配置

必须加上

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c">
<!--    p namespace,可以直接注入属性的值-->
    <bean id="user" class="com.jj.User" p:age="18" p:name="zhao"/>
<!--    c namespace,需要构造有参构造方法,同时记得构造无参构造方法,否则报错-->
    <bean id="user1" class="com.jj.User" c:age="18" c:name="bb"/>
</beans>

实例分析

User class

package com.jj;

public class User {
    private int age;
    private String name;

    public User() {
    }

    public User(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

程序执行

import com.jj.Student;
import com.jj.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.swing.text.AbstractDocument;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context2=new ClassPathXmlApplicationContext("ApplicationContext2.xml");
        User user= (User) context2.getBean("user1");
        System.out.println(user);

    }
}

运行结果 

2.3 bean scope

 浏览器翻译成中文,可以讲究看看

        1.单例模式(spring默认)每次创建都是同一个对象 scope=“singleton"

        2.原型模式:每次创建都是新对象scope="prototype"

        3.request,session,application都在web开发中用到

3 Spring 配置

3.1 别名 (alias)

<bean id="user" class="xxxx"/>
<alias name="user" alias="uuuserrr"/>

3.2 bean

id:唯一标识符,相当于对象名

class:bean对象对应的全限定名:包名+类型 (com.jj.xxx)

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

<property>下配置参数

<bean id="user" class="com.jj.xxx" name="user2 u1,u2;u3>
<property name="name" value="xxxxxx"/>
</bean>

3.3 import

团队开发使用,将多个配置文件,导入合并一个

<import resource="applicationContext1"/>
<import resource="applicationContext2"/>
<import resource="applicationContext3"/>

4 Bean的自动装配

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

        spring会自动上下文寻找。并自动给bean装配属性

在spring中有三种装配方式:

        在xml中显示配置

        在java中显示配置

        隐式的自动装配bean(重要)

byName:自动在容器上下文查找和自己对象set方法后面的值对应的bean id

byType:自动在容器上下文查找和自己对象属性类型相同的bean

实例:

autowire="byName"

要保证bean id唯一,并且id值与对象set方法后面的值一样

    <bean id="dog" class="com.jj.Dog"/>
    <bean id="cat" class="com.jj.Cat"/>
    <bean id="people" class="com.jj.People" autowire="byName">
        <property name="name" value="zhao"/>
    </bean>

autowire="byType"  

保证class唯一,同一个class只能bean一个

    <bean id="dog" class="com.jj.Dog"/>
    <bean id="cat" class="com.jj.Cat"/>
    <bean id="people" class="com.jj.People" autowire="byType">
        <property name="name" value="zhao"/>
    </bean>

使用注解实现自动装配

须知:

        导入约束

        配置注解的支持

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

<context:annotation-config/>

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

用了Autowired可以不用编写set方法,前提是自动装配的属性在IOC,且符合byname或者bytype

 

如果两个cat型不同名字的cat,可加@Qualifier(value=" ")来指定指向哪个

 

 @Resource注解也可以,用法类似@Autowired

区别:

        @Autowire默认通过byType,不满足则通过byName

         @Resource相反

5.自动注解开发

5.1 前序准备:

        aop包导入

         约束导入

<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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/context/spring-aop.xsd">
    <!--    开启注解的支持-->
    <context:annotation-config/>
<!--    扫描包,包下的注解就会生效-->
    <context:component-scan base-package="com.jj.pojo"/>
<!--    <bean id="user" class="com.jj.pojo.User"/>-->
</beans>

 5.2 属性注入

package com.jj.pojo;

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

@Component
public class User {
    @Value("zhao")
    public String name;
}

5.3 衍生的注解

@Component有几个衍生注解,这几个注解功能一样,代表将某个类注册到spring中,装配bean,我们在web开发中,按照mvc三层架构分层

        dao :@Repository

        service:@Service

        controller:@Controller

5.4 作用域

@Scope(value = "singleton")

@Scope(value = "singleton")

总结:

        xml比较万能,适用于任何场景!维护简单方便

        注解不是自己的类使用不了,维护复杂

        最佳实践:xml管理bean,注解只负责完成属性的注入

        特别注意:如让注解生效,需要开启注解支持

6. 使用java的方式配置spring

        javaconfig是spring的一个子项目,spring4后成为核心

实例

UserConfig class

package com.jj.config;


import com.jj.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

//这里也会被spring容器托管,它本身也是一个@component
//@configuration代表只是一个配置类,类似applicationContext.xml
@Configuration
@ComponentScan("com.jj.pojo")
@Import(UserConfig2.class) //导入其他类,合并使用
public class UserConfig {
    //注册bean,相当于在xml中写一个bean标签
    //方法的名字,相当于bean中的id
    //方法的返回值,相当于bean中的class
    //<bean id="getUser" class="User"/>
@Bean
    public User getUser(){
        return new User(); //返回要注入到bean的对象
    }
}

User class

package com.jj.pojo;

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

@Component
public class User {

    private String name;

    public String getName() {
        return name;
    }
@Value("zhao")
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

执行程序

import com.jj.config.UserConfig;
import com.jj.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(UserConfig.class);
        User user= (User) context.getBean("getUser");
        System.out.println(user.getName());
    }
}

结果

注意:

new context的时候使用的是AnnotationConfigApplicationContext,括号内要填写索要引用class的class,例如:UserConfig.class

7.代理模式

7.1静态代理

一般有以下角色,以房东出租房,房客承租房为例:

抽象角色:一般用接口或者抽象类,出租房视为一个抽象接口

真实角色:被代理的角色,房东视为想要出租房的真实角色

代理角色:代理真实角色,一般会做一些附属操作,中介视为代理对象

客户:访问代理对象的人,房客视为客户

代理模式优点:

        真实角色操作更纯粹,不用关注一些公共业务

        公共业务交给代理,实现业务分工

        公共业务扩展方便集中管理

缺点:

        每个真实角色都会产生一个代理角色,代码量多,效率低

编写代码步骤:

        1.出租的接口

package com.jj.demo01;

//出租房,抽象一般用接口
public interface Rent {
    void rent();
}

        2.真实角色,房东继承出租接口

package com.jj.demo01;

public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("我是房东");
    }
}

        3.代理角色,代理也要继承出租接口

package com.jj.demo01;

public class Proxy implements Rent{
    private Host host;

    public Proxy() {
    }
    public Proxy(Host host) {
        this.host = host;
    }
    public void rent(){
        host.rent();
    }
}

        4.客户访问代理

package com.jj.demo01;

public class Client {
    public static void main(String[] args) {
        Proxy proxy=new Proxy(new Host());
        proxy.rent();
    }
}

代理的作用:比如纵向流程已开发全部可用,现在要在service增删改,但不希望破坏原有流程的所有东西,则使用代理来代理service实现不改动源代码而做修改

7.2 动态代理

        与静态代理的角色一样

        动态代理的代理类是动态生成的,不直接写好

        动态代理分为两大类:

                基于接口的动态代理--JDK动态代理

                基于类--cglib

                        java字节码实现--javasist

动态代理重要类:Proxy,InvocationHandler(调用处理程序)

动态代理这节有点难理解,听了没太懂,我准备专门整理一章来记录我的理解。

JDK 动态代理_halo321的博客-CSDN博客

如果有对动态代理有独特理解的大神,欢迎评论区指导。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值