• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
在赶路的我
博客园    首页    新随笔    联系   管理    订阅  订阅

Spring

Spring5学习

spring5简介


spring简介(spring给软件行业带来了春天)

  • 作用:减少企业应用开发的复杂性
  • 历史:2004年,以interface21框架为基础推出的spring框架。有Rod Johnson开发springframeword
  • 理念:使现有的技术变得更加容易使用,整合现有的框架,是一个大杂烩

spring下的框架(SSM和SSH)

  • SSM(现在使用最多):Spring+SpringMVC+Mybatis(半自动持久化框架)
  • SSH:Spirng+Struct2+Hibernate(全自动持久化框架)

spring优点与缺点

  • 优点:开源免费,轻量级非侵入式框架。支持事务处理。对框架的整合。AOP(控制反转)和IOC(面向切面编程)

spring5的组成与拓展


spring的组成(由三大思想和七大模块)

  • 三大思想:AOP(面向切面),IOC(控制反转),DIC(依赖注入)
  • 七大模块:springweb,springwebmvc,spirngcontext,springdao,springcore,springorm,springaop

拓展(基于现代化的java开发,就是基于spring开发)

  • springboot--->springcloud--->springdataflow
  • springboot:是基于spring应用开发的一个脚手架,springboot可以快速开发一个基于spring的应用程序,以构建微服务(约定大于配置),旨在通过最少的前期配置尽快启动应用
  • springcloud:是治理微服务的,springcloud-netflix是一站式微服务解决方案

为什么springboot会出现

  • spring发展太快,之后就有了弊端,原来旨在使现有的技术更容易使用,但是spring发展太快,导致配置繁杂,人称配置地狱,于是springboot出现了,帮我们自动配置了许多配置

springIOC理论推导


简单理解

  • 相当于工厂,超市,消费者的关系
  • 没有IOC:消费者需要什么,由工厂生产并直接送给消费者,工厂要做的是生产和配送,需要和消费者打关系,很麻烦
  • 有IOC:消费者需要什么,由工厂生产,然后给超市,消费者在超市拿就可以,这个工厂和消费者就不用打交道,工厂专心负责生产就可以了,比较轻松。实现了消费者和工厂的解耦

IOC容器创建对象的三种方式


无参构造创建对象

<bean id="usernameimpl" class="com.chen.dao.usernameimpl"/>

有参构造创建对象

//指定参数名字
<bean id="userseximpl" class="com.chen.dao.userseximpl">
        <constructor-arg name="sex" value="男"></constructor-arg>
</bean>
//指定参数类型
<bean id="userseximpl" class="com.chen.dao.userseximpl">
        <constructor-arg type="java.lang.String" value="男"></constructor-arg>
</bean>
//指定参数下标
<bean id="userseximpl" class="com.chen.dao.userseximpl">
        <constructor-arg index="0" value="男"></constructor-arg>
</bean>

工厂模式创建对象

//通过工厂模式来创建bean对象
//第一步首先创建自定义工厂bean
    <bean id="factory" class="com.chen.dao.MyBeanFactory"/>
//第二步通过工厂模式来创建bean对象
    <bean id="usernameimpl2" factory-bean="factory" factory-method="getUsernameimpl"/>

spring配置说明


bean的配置说明

  • id:是bean的唯一标识,以后通过他它来拿到bean
  • name:也是bean的标识,只不过name可以有多个,用分号或则逗号或者空格分开,以后也可以使用他来拿到bean
  • class:是bean的位置
<bean name="usernameimpl3 usernameimpl4" id="usernameimpl" class="com.chen.dao.usernameimpl"/>

alias的配置说明

  • name:是bean的name或者id属性
  • alias:是指定bean的别名,以后也可以通过他来拿到bean
    <bean name="usernameimpl3 usernameimpl4" id="usernameimpl" class="com.chen.dao.usernameimpl"/>
    <alias name="usernameimpl3" alias="usernameimpl5"/>

import的配置说明

  • 作用:可以将多个bean.xml合并为一个ApplicationContext.xml,适用于团队开发
<import resource="beans.xml"/>

spring依赖注入(DI)的方式


一共有三种方式

  1. 有参构造注入依赖

  2. set注入依赖(重点) set方式可以实现多种复杂类型的依赖注入

  3. 拓展方式注入:需要引入第三方的工具

xmlns: c="http://www.springframework.org/schema/c或者p"
//c:对应构造器注入  p:对应set方式注入

spring依赖注入之set注入(重点)


Test类

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Test {

    private String name;
    private Test2 test2;
    private List<String> names;
    private Set<String> ages;
    private Map<String,String> hobbys;
    private Properties properties;
    private String dd;

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

    public void setTest2(Test2 test2) {
        this.test2 = test2;
    }

    public void setNames(List<String> names) {
        this.names = names;
    }

    public void setAges(Set<String> ages) {
        this.ages = ages;
    }

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

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

    public void setDd(String dd) {
        this.dd = dd;
    }

    @Override
    public String toString() {
        return "Test{" +
                "name='" + name + '\'' +
                ", test2=" + test2 +
                ", names=" + names +
                ", ages=" + ages +
                ", hobbys=" + hobbys +
                ", properties=" + properties +
                ", dd='" + dd + '\'' +
                '}';
    }
}

set注入的类型

    <bean id="Test" class="Test">
<!--        引用类型的注入-->
        <property name="test2" ref="Test2"/>
<!--        普通类型的注入-->
        <property name="name" value="陈浪涛"/>
<!--        空值得注入-->
        <property name="dd">
            <null></null>
        </property>
<!--        list集合的注入-->
        <property name="names">
            <list>
                <value>list集合</value>
                <value>list集合</value>
                <value>list集合</value>
                <value>list集合</value>
            </list>
        </property>
<!--        set集合的注入-->
        <property name="ages">
            <set>
                <value>set集合1</value>
                <value>set集合2</value>
                <value>set集合3</value>
                <value>set集合4</value>
            </set>
        </property>
<!--        map集合的注入-->
        <property name="hobbys">
            <map>
                <entry key="1" value="map集合"/>
                <entry key="2" value="map集合"/>
                <entry key="3" value="map集合"/>
                <entry key="4" value="map集合"/>
            </map>
        </property>
<!--        properties的注入-->
        <property name="properties">
            <props>
                <prop key="1">prop1</prop>
                <prop key="2">prop2</prop>
                <prop key="3">prop3</prop>
                <prop key="4">prop4</prop>
            </props>
        </property>
    </bean>

tostring结果

Test{name='陈浪涛', test2=Test2@627551fb, names=[list集合, list集合, list集合, list集合], ages=[set集合1, set集合2, set集合3, set集合4], hobbys={1=map集合, 2=map集合, 3=map集合, 4=map集合}, properties={4=prop4, 3=prop3, 2=prop2, 1=prop1}, dd='null'}

Bean的作用域


bean的作用域配置 scope,一共有四个属性

  • prototype:原型模式,每个实例都不一样
  • singleton:单例模式, 只有一个实例
  • request:web中用到
  • session:web中用到

如singleton测试,只有一个实例,hashcode一样

    <bean id="Test" class="Test" scope="singleton">
<!--        引用类型的注入-->
        <property name="test2" ref="Test2"/>
<!--        普通类型的注入-->
        <property name="name" value="陈浪涛"/>
<!--        空值得注入-->
        <property name="dd">
            <null></null>
        </property>
<!--        list集合的注入-->
        <property name="names">
            <list>
                <value>list集合</value>
                <value>list集合</value>
                <value>list集合</value>
                <value>list集合</value>
            </list>
        </property>
<!--        set集合的注入-->
        <property name="ages">
            <set>
                <value>set集合1</value>
                <value>set集合2</value>
                <value>set集合3</value>
                <value>set集合4</value>
            </set>
        </property>
<!--        map集合的注入-->
        <property name="hobbys">
            <map>
                <entry key="1" value="map集合"/>
                <entry key="2" value="map集合"/>
                <entry key="3" value="map集合"/>
                <entry key="4" value="map集合"/>
            </map>
        </property>
<!--        properties的注入-->
        <property name="properties">
            <props>
                <prop key="1">prop1</prop>
                <prop key="2">prop2</prop>
                <prop key="3">prop3</prop>
                <prop key="4">prop4</prop>
            </props>
        </property>
    </bean>

        
测试结果:
        1651855867
		1651855867

Bean的自动装配(autowire)


自动装配概念

  • 自动装配是spring满足bean依赖注入的一种方式,spring会在容器中上下文中自动寻找,并自动给bean注入依赖

spring中的三种装配方式

  1. 在bean.xml中显示的装配
  2. 在java config中显示的装配
  3. 隐式的装配(自动装配)(重点)

自动装配的方式

  • byName:容器中有id(这个id是小写的,才有效)和被装配bean中的set方法set后面的名字相同的bean并注入
  • byType:容器中有class类型与被装配bean中的属性相同类型就注入
  • constructor:容器中有类型为被装配bean中有参构造中的参数相同类型相同就注入
  • default
  • no
    <bean id="Test" class="Test" scope="singleton" autowire="constructor">
<!--        引用类型的注入-->
<!--        <property name="test2" ref="Test2"/>-->
<!--        普通类型的注入-->
        <property name="name" value="陈浪涛"/>
<!--        空值得注入-->
        <property name="dd">
            <null></null>
        </property>
<!--        list集合的注入-->
        <property name="names">
            <list>
                <value>list集合</value>
                <value>list集合</value>
                <value>list集合</value>
                <value>list集合</value>
            </list>
        </property>
<!--        set集合的注入-->
        <property name="ages">
            <set>
                <value>set集合1</value>
                <value>set集合2</value>
                <value>set集合3</value>
                <value>set集合4</value>
            </set>
        </property>
<!--        map集合的注入-->
        <property name="hobbys">
            <map>
                <entry key="1" value="map集合"/>
                <entry key="2" value="map集合"/>
                <entry key="3" value="map集合"/>
                <entry key="4" value="map集合"/>
            </map>
        </property>
<!--        properties的注入-->
        <property name="properties">
            <props>
                <prop key="1">prop1</prop>
                <prop key="2">prop2</prop>
                <prop key="3">prop3</prop>
                <prop key="4">prop4</prop>
            </props>
        </property>
    </bean>

注意点

  • byName:保证容器中id唯一
  • byType:保证容器中class类型唯一

注解实现自动装配


导入约束

<?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">
</beans>

开启注解支持

//是用于激活那些已经在spring容器里注册过的bean上面的注解
<context:annotation-config/>

使用注解

    @Autowired
    @Qualifier(value = "test2")
    private Test2 test2;

	@Resource(name = "test2")
	private Test2 test2;

注意点

  • 必须要在bean.xml中开启注解支持,即是spring能识别到注入,否则无效
  • spring容器中必须有自动装配所需要的bean
  • @Autowired默认使用byType来实现装配,所以如果遇到多个id对应一个class类型的时候,可以用@Qualifier(value="")来指定要使用那一个bean
  • 使用@Autowired只要保证spring容器中有所需要的bean即可,可以不用在实例中写set方法和有参构造

拓展

  • @Resource注解也可以完成自动装配,默认是按byName实现,相当于@Autowired和@Aualifier的升级版,是java自带的,当有多个id对应一个class时候,@Resource(name="")来指定用哪个
  • @Nullable注解可以使标记的属性可以为空不报错
  • @Autowired(required=false)标识装配的bean可以为空,默认为true,不为空,否则报错

spring使用注解开发


还是要导入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
       https://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
</beans>

开启包扫描

//该配置项其实也包含了自动注入上述 四个processor 的功能,因此当使用 < context:component-scan/> 后,	就可以将 < context:annotation-config/> 移除了
<context:component-scan base-package="com.chen"/>

在需要使用注解开发的地方使用注解即可

介绍spirng使用注解开发的一些常用注解

  • @component: 用在类上,被这个注解标记的类,就可以被注册到springioc容器中了
  • @reposity:用在Dao层上,被这个注解标记的了诶,就可以被注册到springioc容器中了
  • @service:用在Service层上,被这个注解标记的了诶,就可以被注册到springioc容器中了
  • @controller:用在Controller层上,被这个注解标记的了诶,就可以被注册到springioc容器中了
  • @value: 用在属性或者set方法上,可以为属性或者set方法对应的类型注入值

@reposity,@service,@controller是@component的延伸版,用于区分不同层的组件罢了

使用注解开发和使用xml文件开发的优缺点

  • 注解的优点:方便
  • 注解的缺点:维护不方便,而xml适用于任何场景

所以spring开发注解开发和xml开发可以结合使用,注解用于给属性注入值,xml用于管理bean

注意点

  • context:annotation-config

而使用context:annotation-config/ 就可以隐式地自动向Spring容器注册4个BeanPostProcessor

AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
    
这样就可以使用@ Resource 、@ PostConstruct、@ PreDestroy、@PersistenceContext、@Autowired、@Required等注解了,就可以实现自动注入
注册这4个 BeanPostProcessor的作用,就是为了你的系统能够识别相应的注解。
  • context:component-scan

Spring给我们提供了context:annotation-config 的简化的配置方式,自动帮助你完成声明,并且还自动搜索@Component , @Controller , @Service , @Repository等标注的类。

context:component-scan除了具有context:annotation-config的功能之外,context:component-scan还可以在指定的package下扫描以及注册javabean 。还具有自动将带有@component,@service,@Repository等注解的对象注册到spring容器中的功能。

因此当使用 context:component-scan 后,就可以将 context:annotation-config移除。

spring使用java config来充当xml配置文件(springboot常见)


使用javaconfig来注册bean要知道的注解

  • @Configuration: 在配置类上使用,被标记的类就相当于xml中的
  • @ComponentScan: 相当于xml中的 <context: component-scan=""/>
  • @Import:相当于xml中的import,将多个配置类合并成一个
  • @Bean:在@Configuration标记的类中使用它,可以将方法所对应的返回类型bean注册到springioc容器中
@ComponentScan(basePackages = "com.chen.service")
@Configuration
@Import(MyConfig2.class)
public class MyConfig {

    @Bean
    //在这里Dao类型的bean被注册到容器中,id为dao,也就是方法名 class就是返回的class类型
    public Dao dao(){
        return new Dao();
    }

}

测试

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println(context.getBean("dao"));

注意:1.这里的容器实现类是AnnotationConfigApplicationContext,而xml使用的是ClassPathXmlApplicationContext。2.@Configuration的地层也是一个组件,最终也会被放到spring容器中

spring的静态代理模式


静态代理在理解


代码层面理解静态代理

一个实现类实现了一个接口,在不改变原来实现类的代码情况下,在新建一个类实现这个接口,导入原来的实现类的对象,
在不需要改动的方法继续调用原来实现类的方法,在需要增加业务的方法中调用原来的方法,并且添加业务代码,实现在不改变原来实现类代码的情况下,新增了业务代码,在这里,新增实现类就起到了代理的作用

动态代理


以Jdk反射实现动态代理需要了解的类个接口

  • InvocationHandler接口和Proxy类

InvocationHandler和Proxy作用

  • InvocationHandler:关联Proxy,其中有一个方法是invoke,可以执行关联的代理类的所有方法,所有的增加的代码可以写在代理类的方法的前后,以此来增强原来的方法。
  • Proxy:他的方法newProxyInstance()方法可以创建对应对象的代理类

用法

  • 新建一个工具类实现InvocationHandler接口,重写invoke方法,新建一个get方法返回Porxy创建的代理类
package com.chen.proxyutil;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyProxy implements InvocationHandler {

    private Object impl;

    public MyProxy(Object impl){
        this.impl=impl;
    }

    public MyProxy(){}

    public Object getImpl() {
        return impl;
    }

    public void setImpl(Object impl) {
        this.impl = impl;
    }

    public Object getImplProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), 			                    impl.getClass().getInterfaces(),this);

    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法执行前新增业务代码");
        Object invoke = method.invoke(impl, args);
        System.out.println("方法执行后新增业务代码");
        return invoke;
    }
}

  • 使用方法
        //有DaoInterface接口,实现类Dao
		Dao dao = new Dao();
        MyProxy myProxy = new MyProxy(dao);
        DaoInterface implProxy = (DaoInterface) myProxy.getImplProxy();
        System.out.println(implProxy.getDao());
  • 运行结果
代理类方法执行前新增业务代码
代理类方法执行后新增业务代码
我是dao

spring-aop(原理是动态代理)


使用注解实现AOP

  • 了解aop中的一些名词
  1. 目标对象:指要被代理的实现类
  2. 切面:指包含增强实现类方法的类
  3. 通知:指切面中的一个个的方法
  4. 切入点:指实现类中指定范围的方法的集合
  5. 连接点:指实现类中任意的一个方法
  • 通知的分类
  1. 前置通知(@Before(value="")):在连接点前通知
  2. 环绕通知(@Around(value="")): 在连接点执行前后通知
  3. 最终通知(@AfterRetruning(value="")):在连接点正常执行完后通知并且知道方法的返回值
  4. 后置通知(@After(value="")):不管连接点怎么用,在连接点执行完后通知
  5. 异常通知(@AfterThorwing(value="")):在连接点出现异常时候通知,并且可以访问到异常对象

步骤

  1. 导入支持aop编程的依赖
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
  1. 自定义切面(要加上@Aspect注解)
package com.chen.aspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component(value = "aspect")
//开启切面
@Aspect
public class DiyAspect {
    
	//value的值是指定插入的连接点,这里的连接点是PersonImpl中的所有方法
    @Before(value = "execution(* com.chen.dao.PersonImpl.*(..))")
    public void before(){
        System.out.println("连接点执行前");
    }
    @After(value="execution(* com.chen.dao.PersonImpl.*(..))")
    public void after(){
        System.out.println("连接点执行后");
    }

}
  1. 测试接口
package com.chen.dao;

import org.springframework.stereotype.Repository;


public interface Person {

    void getName();
    void getSex();

}

  1. 实现类
package com.chen.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "personImpl")
public class PersonImpl implements Person{


    @Override
    public void getName() {
        System.out.println("陈浪涛");
    }

    @Override
    public void getSex() {
        System.out.println(21);
    }


}

  1. 测试
连接点执行前
21
连接点执行后
连接点执行前
陈浪涛
连接点执行后

关于@Before(value="")的value值

  • 示例1:execution(* com.chen.dao.PersonImpl.*(..))
第一个*:表示任意的返回类型
*(..):表示PersonImpl类下的任意类型参数的方法
  • 示例2:execution(* com.chen.dao.*.*(..))
表示com.chen.dao下的任意类任意参数的方法

其他面向切面的方法(笔记上有)

  • 使用原生的Spring API实现
  • 自定义切面实现

整合Mybatis

  • 导入依赖
mybatis-spring
posted @ 2023-02-25 16:40  在赶路的我  阅读(7)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3