Spring 简介

在线快速搭建基于Spring的SpringBoot项目

1、概述

1、Spring 诞生于 2003 年,是对早期 J2EE 规范复杂性的响应,使创建 Java 企业应用程序变得非常简单
2、除了Java语言,还支持 Groovy 和 Kotlin 作为 JVM 上开发的替代语言
3、从 Spring Framework 6.0 开始, Spring 需要 Java 17+ 的支持

  • 包含模块
    1、Spring 框架拥有多个模块,其核心是容器模块,包括【配置模型】和【依赖注入】
    2、Spring 框架还提供了一些基础功能用于支持不同的应用程序架构,包括【消息传递】、【事务数据】、【持久性】和【网络】,同时还包括基于【Servlet 的 Spring MVC Web 框架】、【Spring WebFlux 响应式 Web 框架】
    3、Spring框架除了自身之外还拥有其它项目,如Spring Boot,Spring Cloud,Spring Security,Spring Data,Spring Batch等等

2、核心技术

2.1 IOC容器

IOC容器(控制反转)是Spring框架的核心,又被称为DI(依赖注入)。将原本需要由开发者自行创建Bean的工作交由容器来完成,通过容器来实现Bean的管理(实例化、配置和组装)

1、【org.springframework.beans】包 和 【org.springframework.context】包 是Spring IoC容器的实现基础
2、【BeanFactory】接口是实现Spring容器相关功能的顶级接口,默认Bean采用的是延迟加载机制
3、【ApplicationContext】接口是【BeanFactory】的子接口,默认采用的是实时加载Bean,添加一些额外功能(事件传播、电子邮件、调度器、国际化等等

注意:不建议使用基于 xml 方式来配置元数据,更推荐使用基于 JAVA 代码的方式来配置元数据

2.2 Bean(IOC容器管理的对象)

2.2.1 FactoryBean(为容器提供自定义Bean实例化过程的工厂接口)

@Component
public class DemoFactoryBean implements FactoryBean<Demo> {
    // 该方法返回该 FactoryBean 生产的对象。我们需要实现该方法以给出自己对象实例化逻辑
    @Override
    public Demo getObject() throws Exception {
        Demo demo = new Demo();
        demo.setDesc("DemoFactoryBean");
        return demo;
    }
    
    // 返回 FactoryBean 生产的对象类型。如果预先无法确定,则返回null
    @Override
    public Class<?> getObjectType() {  return Demo.class; }
    
    // FactoryBean 生产的对象是否要以singleton(单例)形式存于容器中
    @Override
    public boolean isSingleton() { return true; }
}
@Controller
@RequestMapping("demo")
public class DemoController {
@Resource
    private DemoFactoryBean demoFactoryBean;
}

2.2.2 自定义 Bean 并纳入容器管理

当我们需要配置大量的Bean或者配置的bean实例化时需要依赖其它的Bean,通过标签的方式来配置bean就会显的很臃肿,针对对以上情况推荐使用@Configuration和@Bean注解实现Java代码的方式来配置Bean,将创建Bean的具体过程交由开发人员把控

@Configuration
public class Demo{
    public Demo() {
        System.out.println("第1步:容器初始化");
    }
    @Bean(value = "demo", initMethod = "myInit", destroyMethod = "myDestroy")
    // singleton 首次创建,多次从缓存中取
    // prototype每调用一次创建一个新的实例
    // request 每一个请求创建一个新的实例
    // session 同一个session共享同一个实例
    @Scope("singleton")
    public Demo getDemo() {
        System.out.println("第1.1步:初始化容器中的bean");
        Demo demo = new Demo();
        demo.setDesc("测试Bean的生命周期");
        return demo;
    }
}

2.3 AOP

OOP即面向对象编程,通过调用方法来实现某些功能,无需关注方法实现细节
AOP是对 OOP 的补充,将通用功能封装成独立的模块,在合适的时机将这些模块横向切入到应用中的指定位置,达到不更改原有代码结构的基础上对代码的功能进行增强

1、前后端分离加密传输数据,对前端发起的请求进行拦截,获取请求中的加密参数进行解密,处理完业务后对响应的参数进行拦截加密处理,最后把相关的入参和出参信息记录到数据库保存

  • 配置案例
1:通过@Aspect注解开启AOP功能
2:通过@Pointcut注解定义切点(设置切入位置)
3:通过通知类型来实现具体的业务逻辑
前置通知(@Before):方法执行之前,执行通知
成功后置通知(@AfterReturning):方法执行成功之后,执行通知
异常后置通知(@AfterThrowing):方法执行异常之后,执行通知
最终后置通知(@After):方法执行之后,不考虑其结果,执行通知
环绕通知(@Around):在方法调用之前和之后,执行通知

2.4 其它

静态代理

静态代理虽然可以实现(不改变原有代码结构的基础上对代码的功能进行增强)功能,但是随着需要代理模块数量增加,开发者需要手写更多的代码
public interface LaboratoryService {
    void add(Demo demo);
}

@Service
public class LaboratoryServiceImpl implements LaboratoryService {
    @Override
    public void add(Demo demo) {
        System.out.println("LaboratoryServiceImpl新增");
    }
} 
以上LaboratoryServiceImpl 类实现了“新增”功能,如果在执行的过程中还想记录该功能的入参和出参的记录:
1、直接在add方法里写,但会增加代码的耦合度,破坏代码的原有结构 
************************************************************************************************
2、通过静态代理实现
@Service
public class LaboratoryServiceProxyImpl implements LaboratoryService {
    @Resource
    private LaboratoryServiceImpl laboratoryService;
    @Override
    public void add(Demo) {
        System.out.println("LaboratoryServiceProxyImpl代理新增");
        laboratoryService.add();
    }
}
// 当一个接口有多个实现类时,注入时要指定名称或者类型来指定具体的实现类
@Resource(name = "laboratoryServiceProxyImpl")
private LaboratoryService laboratoryService;
@RequestMapping("staticProxy")
public Object staticProxy() {
    laboratoryService.add();
    return ResponseUtil.success();
}
//
以上 LaboratoryServiceProxyImpl 类在原有LaboratoryServiceImpl 类的“新增”的基础上实现了入参和出参的记录功能

动态代理

在代码运行期间通过反射来动态调用代理类中的方法
基于接口实现(JDK动态代理)
public class JdkProxyUtil implements InvocationHandler {
    // TODO 我要代理谁,就传入谁的实例对象
    private Object target;
    public JdkProxyUtil() {}
    public JdkProxyUtil(Object target) { this.target = target;}
    // TODO 通过Proxy类来创建 [代理类] 的实例对象
    public Object getProxy() {
        return Proxy.newProxyInstance(
                this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this
        );
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JdkProxyUtil动态代理");
        // TODO 通过反射执行代理类的方法
        Object result = method.invoke(target, args);
        return result;
    }
}
//
@Resource()
private LaboratoryService laboratoryService;
@RequestMapping("staticProxy")
public Object staticProxy() {
    LaboratoryService proxy = (LaboratoryService) new JdkProxyUtil(laboratoryService).getProxy();
    proxy.add();
    return ResponseUtil.success();
}

事件传播(观察者模式)

场景案例:订单入库成功后,需要发送短信通知用户。一般情况都会把短信通知加在订单入库的后边,这样做违反了单一职责(订单保存功能里变不应该杂糅消息通知功能),如果后期需要添加微信消息通知功能,则需要在原有的基础上进行额外添加,这样做又违反了开闭原则(对拓展开放,对修改关闭)。优化方案:通过观察者模式使创建订单和消息通知功能进行分离

@Controller
@RequestMapping("test")
public class TestController {
    @Resource
    private ApplicationContext applicationContext;

    @GetMapping("event")
    @ResponseBody
    public Object event() throws Exception {
        // TODO 创建事件
        OrderSaveEvent orderSaveEvent = new OrderSaveEvent(this,"000000","创建成功");
        // TODO 发布事件
        applicationContext.publishEvent(orderSaveEvent);
        return ResponseUtil.success();
    }
}
  • 自定义订单保存成功事件
public class OrderSaveEvent extends ApplicationEvent {
    private String orderNum;
    public String getOrderNum() { return orderNum; }
    public void setOrderNum(String orderNum) { this.orderNum = orderNum; }

    private String desc;
    public String getDesc() { return desc; }
    public void setDesc(String desc) { this.desc = desc; }

    public OrderSaveEvent(Object source, String orderNum, String desc) {
        super(source);
        this.desc = desc;
        this.orderNum = orderNum;
    }
}
  • 短信通知监听器(接口、无序)
@Component
@Async("asyncTaskExecutor")
public class OrderSmsListener implements ApplicationListener<OrderSaveEvent> {
    @Override
    public void onApplicationEvent(OrderSaveEvent event) {
        LoggerUtil.info(MessageFormat.format("短信提示:订单【{0}】{1}",event.getOrderNum(),event.getDesc()));
    }
}
  • 微信通知监听器(注解、无序)
@Component
@Async("asyncTaskExecutor")
public class OrderSmsListener {
    @EventListener
    public void sms(OrderSaveEvent event) {
        LoggerUtil.info(MessageFormat.format("微信提示:订单【{0}】{1}",event.getOrderNum(),event.getDesc()));
    }
}

3、相关框架

3.1 SpringMVC

SpringMvc是Spring框架中的一部分,基于JAVA实现MVC的WEB框架,其核心就是通过前端控制器(DispatcherServlet)将请求分发到不同的控制器(早期通过继承HttpServlet类实现该功能,Spring2.5开始通过@Controller实现)

启动原理

应用启动时会读取(webapp/WEB-INF/web.xml)文件来加载Spring容器(applicationContext.xml)和Servlet容器(dispatcher-servlet.xml)

  • applicationContext.xml(Spring容器)
    扫描相关类并纳入IOC容器(@Component、@Service、@Repository等等)
    配置数据库连接池和事务
    自定义Bean

  • dispatcher-servlet.xml(Servlet容器)
    扫描相关类并纳入IOC容器(@RestController、@Controller)
    配置静态资源解析器、视图解析器、文件上传解析器
    配置拦截器

3.2 SpringBoot

SpringBoot是Spring框架中的一部分,相比于SpringMvc更加灵活,开箱即用:
1、内置Web容器,可以通过Jar的方式一键部署
2、提供Actuator模块对系统的运行环境进行监控
3、提供众多"starter"依赖项(通过在pom中引入相关starter,即可自行根据当前SpringBoot主版本号自动加载相关Jar包。通过spring-boot- start-web即可自动添加相关SpringMVC的Jar[spring-core、spring-web、spring-webmvc])

SpringBootApplication(复合注解)

SpringBoot项目创建成功后,会在启动类上使用SpringBootApplication符合注解修饰,该注解包含以下三个注解:

  • 1、@ComponentScan
    对主应用文件(项目名Application)所在目录下的文件进行扫描,加载符合条件的组件(@Component、@Service、@Controller、
    @RestController)纳入IOC容器

  • 2、@EnableAutoConfiguration
    将主应用文件(项目名Application)所在目录中符合自动配置条件(被@Configuration修饰的类)的Bean纳入IOC容器

  • 3、@SpringBootConfiguration
    该注解继承@Configuration,被@Configuration修饰的类都会成为配置类,相比于传统XML形式配置Bean更为简单
    在@Configuration修饰的类中,标注@Bean方法返回的值将作为一个Bean纳入IOC容器,方法的名称为该Bean在容器中的id

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大能嘚吧嘚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值