Spring框架的IOC和AOP的简单项目实现

news2024/9/21 10:45:54

一、Spring框架介绍

Spring框架是为了解决企业应用开发复杂性而创建的,是Java应用钟最广的框架,它的成功来源于设计思想,而不是技术本身,即IOC(inversion of control,控制反转)AOP(Aspect oriented programming,面向切面编程) 的核心概念。它将面向接口的编程思想贯穿整个系统,解决了项目中各层的松耦合问题,简化企业项目的开发。

1、IOC(控制反转)

Spring IOC像是一个容器,认为Java资源都是Java Bean,IOC的目标是管理好Bean。在 Spring IOC里管理了各种 Bean(资源),它们的创建、事件、行为、资源之间的依赖关系等,都由 Spring IOC 容器根据配置文件的描述来完成管理任务。因此,使用 Spring 框架就是将对象的创建、销毁、初始化等一系列生命周期的过程,都交给 Spring 容器来处理。

如果没有IOC?
平常我们写代码,如果一个类ServiceA要调用另一个类ServiceB的某个方法,就需要在类ServiceA的方法里new一个类ServiceB的对象。

假如现在你有几十个类都需要用到ServiceB的某个方法,那你就需要在几十个类里,都分别去new一个ServiceB的对象。

有一天,业务改了,你写了一个新的类ServiceC,类ServiceB就废弃不用了。那之前调用ServiceB的几十个类,你就得把几十个类中
“ServiceB b= new ServiceB ()”的代码改成“ServiceC c= new ServiceC ()”

如果你漏掉了一处,那项目跑的时候又去调用对象ServiceB 的方法,但此时ServiceB 的逻辑已经废弃了…

IOC解决了什么问题?
创建一个接口ServiceB,然后给它创建一个实现类ServiceBImpl。在ServiceA里注入接口ServiceB。

这个时候,当你的项目启动的时候,Spring 容器在底层使用java的反射技术,去扫描项目中的Bean。它首先发现类 ServiceA 里引用了接口ServiceB,然后它去找现在是谁实现了接口ServiceB,它发现原来是类ServiceBImpl实现了接口ServiceB,此时根据这层依赖关系,它就会在类 ServiceA实例化一个ServiceBImpl的对象。依赖注入,就是Spring容器用反射技术,根据注解或配置文件去创建Bean, 然后根据Bean之间的依赖和引入关系,去实例化对应的对象,实现了类和类之间彻底的解耦。

2、AOP(面向切面的编程)

AOP解决了什么问题?
解决重复代码问题。AOP,就是通过动态代理技术生成类的一个动态代理类,这个动态代理类实现了你的类的所有方法,然后根据你的注解,给每个方法织入一些增强代码。从而避免了项目中大量重复代码,一改就得改几十个方法的问题了。

二、简单项目(完整代码)

蛋糕店项目:可以进行制作多种口味(柠檬和芝士)蛋糕操作,输入需要制作的蛋糕口味后,使用AOP模拟实现了在制作开始前检查烤箱是否适合烘培、烘培结束后打包蛋糕、送出蛋糕的功能,制作完成后会输出到控制台。

Cake.java
package cn.java.bean;
public class Cake {
    String type ="";
    public  void addMilk(){

    }
    public  void addFlour(){

    }
    public String getName(){

        return type;
    }
}
CheeseCake.java
package cn.java.bean;
public class CheeseCake extends Cake{
    @Override
    public void addMilk() {
        System.out.println("给蛋糕加牛奶!");
    }

    @Override
    public void addFlour() {
        System.out.println("给蛋糕加面粉!");
    }

    @Override
    public String getName() {
        return "芝士蛋糕";
    }
}
LemonCake.java
package cn.java.bean;
public class LemonCake extends Cake{
    @Override
    public void addMilk() {
        System.out.println("给蛋糕加牛奶!");
    }

    @Override
    public void addFlour() {
        System.out.println("给蛋糕加面粉!");
    }

    @Override
    public String getName() {
        return "柠檬蛋糕";
    }
}
CakeDao.java
package cn.java.dao;
import cn.java.bean.Cake;
public interface CakeDao {
    public int addCake(Cake cake);
}
CakeDaoImpl.java
package cn.java.dao.impl;
import cn.java.bean.Cake;
import cn.java.dao.CakeDao;
public class CakeDaoImpl implements CakeDao {
    @Override
    public int addCake(Cake cake) {
        System.out.println("cake" +"对象信息为:"+cake);
        System.out.println("已将cake订单存入账本");
        return 1;
    }
}
CakeMakeService.java
package cn.java.service;
import org.springframework.stereotype.Service;
@Service
public interface CakeMakeService {
    public void CakeMake(String type);
    public void CakeMakeAndPack(String type);
}
CakeMakeServiceImpl.java
package cn.java.service.impl;

import cn.java.bean.Cake;
import cn.java.dao.CakeDao;
import cn.java.service.CakeMakeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import java.applet.AppletContext;
import java.util.HashMap;
@Service
public class CakeMakeServiceImpl implements CakeMakeService {

    @Override
    public void CakeMake(String type) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        Cake cake = (Cake) context.getBean(type);
        cake.addMilk();
        cake.addFlour();
        String result = cake.getName();
        System.out.println("叮叮叮叮~  "+result+"新鲜出炉!");


    }

    @Override
    public void CakeMakeAndPack(String type) {

        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        Cake cake = (Cake) context.getBean(type);
        CakeDao cakeDaoImpl = (CakeDao) context.getBean("CakeDaoImpl");
        cake.addMilk();
        cake.addFlour();
        String result = cake.getName();
        System.out.println("叮叮叮叮~  "+result+"新鲜出炉!");
        cakeDaoImpl.addCake(cake);
    }
}

CheckBefore.java
package cn.java.aop;

import org.aspectj.lang.annotation.Aspect;
@Aspect
public class CheckBefore {
    public void checkSafe(){
        System.out.println("[AOP前置通知]: 正在检查当前烤箱是否可以开始烘培......");
    }

    public void checkSuc(){
        System.out.println("[AOP前置通知]: 当前机器正常!开始烘培....");
    }

}
DeliveryAfter.java
package cn.java.aop;

import org.aspectj.lang.annotation.Aspect;

@Aspect
public class DeliveryAfter {
    public void deliveryExit(){
        System.out.println("[AOP结束通知]: 已安全送出蛋糕.....");
    }
}
PackAfter.java
package cn.java.aop;

import org.aspectj.lang.annotation.Aspect;
@Aspect
public class PackAfter {
    public void pack() {
        System.out.println("[AOP返回通知]: 正在打包蛋糕....");
    }
}
aop.xml
<!-- 配置目标类,运算bean -->
    <bean id="cakeServiceImpl" class="cn.java.service.impl.CakeMakeServiceImpl" >
    </bean>

    <!--    AOP实验-->
    <!-- 配置切面类,检查bean ,第一个切面-->
    <bean id="CheckBefore" class="cn.java.aop.CheckBefore"></bean>
    <!-- 配置切面类,打包bean ,第二个切面-->
    <bean id="PackAfter" class="cn.java.aop.PackAfter"></bean>
    <!-- 配置切面类,送出bean ,第三个切面-->
    <bean id="DeliveryAfter" class="cn.java.aop.DeliveryAfter"></bean>

    <!--    <aop:config></aop:config>-->

    <!--2. 配置aop,开始将目标方法和各切面中的通知方法,进行织入-->
    <aop:config>
        <!--  配置连接点(切入点)-->
        <aop:pointcut expression="execution (* cn.java.service.impl.CakeMakeServiceImpl.* (..))" id="cakePoint"/>

        <!-- 配置各切面,不要哪个切面时,注释掉即可 -->

        <!--  配置检测检查环境切面 1. CheckBefore,aop:before:表示前置通知
         -->
        <aop:aspect ref="CheckBefore" >
            <aop:before method="checkSafe" pointcut-ref="cakePoint"/>
            <aop:before method="checkSuc" pointcut-ref="cakePoint"/>

        </aop:aspect>

        <!-- 配置打包切面 2:PackAfter,aop:after:表示后置通知
            order="2":表示执行的顺序,数字越大越先执行
         -->
        <aop:aspect ref="PackAfter" order="2">
            <aop:after method="pack" pointcut-ref="cakePoint"/>
        </aop:aspect>

        <!--  配置送出切面 3:DeliveryAfter,aop:after:后置通知
        order="1":表示执行的顺序,数字越大越先执行
        -->
        <aop:aspect ref="DeliveryAfter" order="1">
            <aop:after method="deliveryExit" pointcut-ref="cakePoint"/>
        </aop:aspect>
    </aop:config>
application.xml
 	<bean id="Cake" class="cn.java.bean.Cake">
    </bean>

    <bean id="Lemon" class="cn.java.bean.LemonCake" parent="Cake">
    </bean>

    <bean id="Cheese" class="cn.java.bean.CheeseCake" parent="Cake">
    </bean>


    <bean id="CakeDaoImpl" class="cn.java.dao.impl.CakeDaoImpl">
    </bean>

    <!--   引入局部配置文件  -->
    <import resource="aop.xml"/>
log4j.properties
# log4JÈÕÖ¾¿ò¼ÜµÄÅäÖÃÎļþ ÎļþÃû×Ö²»ÄܸÄ
# DEBUG ±íʾÈÕÖ¾µÄ¼¶±ð  µ÷ÊÔ
# Console ÈÕÖ¾´òÓ¡ÔÚ¿ØÖÆ̨
log4j.rootLogger=INFO, Console 
log4j.appender.Console=org.apache.log4j.ConsoleAppender  
log4j.appender.Console.layout=org.apache.log4j.PatternLayout  
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n  

# ÄÄЩÈÕÖ¾ÐèÒª´òÓ¡
log4j.logger.java.sql.ResultSet=INFO  
log4j.logger.org.apache=INFO  
log4j.logger.java.sql.Connection=DEBUG  
log4j.logger.java.sql.Statement=DEBUG  
log4j.logger.java.sql.PreparedStatement=DEBUG 
test1.java
import cn.java.dao.CakeDao;
import cn.java.service.CakeMakeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test1 {
    @Test
    public void testCalServiceImpl(){
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

        CakeMakeService cakeMakeServiceImp = (CakeMakeService) context.getBean("cakeServiceImpl");

        System.out.println("------------------------CakeMake方法测试------------------------");
        cakeMakeServiceImp.CakeMake("Lemon");
        System.out.println("------------------------------------------------");
        cakeMakeServiceImp.CakeMake("Cheese");
        System.out.println("------------------------------------------------");


        System.out.println("------------------------CakeMakeAndPack方法测试------------------------");
        cakeMakeServiceImp.CakeMakeAndPack("Lemon");
        System.out.println("------------------------------------------------");
        cakeMakeServiceImp.CakeMakeAndPack("Cheese");
        System.out.println("------------------------------------------------");
    }
}

三、运行结果

test1运行结果
请添加图片描述
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2008.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

攻防世界-adworld-reverse-game

#adworld-reverse-game 从1依次输入到8,每个数字会车,最后通关,获得flag |-----------------------▲--------||-----------------------●--------||-----------------------◆--------||-----------------------■--------||--------------------|-----------------------…

vite 静态资源打包配置,echart 主题引入,build上线问题,vue3-echart5使用

文章目录前情提要原因分析实战解析最后前情提要 在经历了vite打包实战后&#xff0c;我入手了echart实战&#xff0c;线下运行一切正常&#xff0c;但是打包上线后出现了异常 TypeError: Cannot create property series onstring <IDOCTYPE html>,挑战又来了&#xff0c…

抖音开发对接之订单取消消息

目录 前言 一、抖音开发中的订单取消消息 二、抖音运营反馈的业务需求分析 三、整体的业务开发思路 四、订单取消消息的代码开发 1.订单取消消息的使用 2.实时保存抖音平台过来的订单取消消息 3.具体的订单业务处理 总结 前言 这里主要是介绍一下抖音开放平台的这个消…

Redis数据结构之字典

目录 字典的应用场景 源码实现 hash算法的实现&#xff0c; hash冲突的解决 扩容缩容机制 哈希表的扩展与收缩条件 渐进式rehash 线程是否安全 Redis的dictht 和 Java(jdk1.8)的HashMap有什么区别 线程安全性 hash算法 解决hash冲突的方法 扩容机制 字典的应用场景…

Navicat的安装及如何将PG库内的数据导出CSV

一、Navicat的安装 1、安装 双击安装 Navicat Premium 12.0.18.0 简体中文 64位.exe 2、编辑连接&#xff0c;进行连接测试 具体配置信息可以进docker容器内查看 二、将PG库内的数据导出CSV 1、进入docker容器&#xff08;docker exec -it postgres_v3 bash&#xff09;&#…

中国开源年会报名 | StarRocks 极速湖仓分析的探索与实践

开源年度盛会 2022 第七届中国开源年会 (COSCon22) 来啦&#xff01; 本次年会将于 10 月 29-30 日由开源社举办&#xff0c;线上共设有1个主论坛和16个分论坛&#xff0c;线下分会场遍布成都、深圳、上海、北京等11个城市。StarRocks PMC 赵恒将代表社区出席大数据专场&#…

【Python】pycharm 和 vscode 编辑器设置模版

author: jwensh time: 2022.10.29 1. pycharm 模版 打开 PyCharm 设置界面&#xff0c;搜索 template&#xff0c;选择 File and Code Templates > Python Script 如下图所示&#xff0c;输入自定义模板代码 模版内容设置 #!/usr/bin/env python # -*- coding: utf-8 -*…

非遗在线商城小程序(后台PHP开发)

目 录 1绪论 1 1.1 选题及意义 1 1.2 国内外文献综述 2 1.3 研究的主要内容 3 2 系统工具 5 2.1 微信小程序 5 2.2 ThinkPHP 5 框架 7 2.3 RESTFul API 8 2.4 微信支付技术 10 2.5 MySQL数据库 12 3 系统分析 14 3.1 市场定位分析 14 3.2 可行性分析 14 3.3 需求目标 14 3.3.1 …

彻底理解Java并发:ReentrantLock锁

本篇内容包括&#xff1a;为什么使用 Lock、Lock 锁注意事项、ReentrantLock 和 synchronized 对比、ReentrantLock &#xff08;加锁、解锁、公平锁与非公平锁、ReentrantLock 如何实现可重入&#xff09;等内容。 一、Lock 锁 1、为什么使用 Lock synchronized 线程等待时间…

Filter快速入门、Filter执行流程、Filter使用细节、Listener概念、分类、ServletContextListener使用

文章目录FilterFilter快速入门Filter 执行流程Filter使用细节ListenerServletContextListener 使用Filter 概念&#xff1a;Filter表示过滤器&#xff0c;是 JavaWeb三大组件&#xff08;Servlet、Filter、Listener&#xff09;之一。过滤器可以把对资源的请求拦截下来&#x…

DASCTF X GFCTF 2022十月挑战赛web

前言 晚来的比赛web题解&#xff0c;这次buu的十月赛web部分的题目对于我来说质量还是蛮高的&#xff0c;因为这几天比较忙&#xff0c;一直没有去复现总结&#xff0c;不过该复现的还得复现&#xff0c;复现了这次比赛又能学到不少知识&#xff0c;嘿嘿嘿。 EasyPOP 考察ph…

Mega-Nerf学习笔记

Mega-NeRF:Scalable Construction of Large-Scale NeRFs for Virtual Fly-Throughs 主页&#xff1a;https://meganerf.cmusatyalab.org/ 论文&#xff1a;https://meganerf.cmusatyalab.org/resources/paper.pdf 代码&#xff1a;https://github.com/cmusatyalab/mega-nerf …

【设计模式】简单工厂模式

简单工厂模式–》工厂模式—》抽象工厂模式 文章目录简单工厂模式定义&#xff1a;各个角色1. 抽象产品类2. 具体产品类&#xff1a;3. 工厂类&#xff1a;简单工厂模式的核心。客户端设计图表未使用简单工厂模式&#xff1a;出现的问题&#xff1a;使用简单工厂模式&#xff1…

小熊派-FreeRTOS-点灯学习过程-20221029

一、前言准备 1、小熊派一个&#xff08;STM32L431RCT6&#xff09; 2、STM32CubeMX 3、keil5 4、小熊派的配套开发资料&#xff08;用于出问题的时候替换&#xff09; 二、实现过程 代码主要由STM32CubeMX生成&#xff0c;所以过程主要是配置CubeMX. 1、芯片选型 STM3…

用 Pyinstaller 模块将 Python 程序打包成 exe 文件(全网最全面最详细)

目录 打包前置知识 一、什么是exe可执行文件&#xff1f; 二、为什么要将 Python 程序打包为 exe 可执行文件&#xff1f; 三、为什么 Python 程序不能直接运行呢&#xff1f; 四、我们用什么来打包 Python 文件呢&#xff1f; 五、打包有哪几种分类呢&#xff1f; 打包…

【ArcGIS微课1000例】0041:ArcGIS利用坐标生成点的方法总结

本文讲解ArcGIS利用坐标生成点的3种方法。 文章目录 一、转到XY工具定位二、输入绝对XY生成点三、添加XY数据一、转到XY工具定位 这样确实可以在图上快速定位某个经纬度的点,但是生成的对象是“注记类”要素,即不是地理实体,而仅仅是为了绘图表现的东西。可以用如下工具来控…

Kotlin协程-并发处理-基础

一、协程与并发 Kotlin协程是基于线程执行的。经过一层封装以后&#xff0c;Kotlin协程面对并发&#xff0c;处理方式与Java不同。 在java的世界里&#xff0c;并发往往是多个线程一起工作&#xff0c;存在共享的变量。需要处理好同步问题。要避免把协程与线程的概念混淆。 …

验证码的编写

编写一个验证码(可以通过键盘输入需要获取验证码的位数)&#xff1a; public class IdentifyingCode {public static void main(String[] args) {//验证码的编写IdentifyingCode identifyingCode new IdentifyingCode();//扫描键盘输入Scanner scanner new Scanner(System.i…

【数据结构基础】之数组介绍,生动形象,通俗易懂,算法入门必看

【数据结构基础】数组前言一、数组的定义1.基本概念和内存图2.数组的性质3.数据结构二、玩转数组1.循环遍历打印数组的每一个值2.查找一个数组里存在的值3.打擂台的形式找最大值4.元素的位移5.数组的扩容6.数组的反转三、二维数组四、初识算法1.排序算法2.查找算法3.算法性能4.…

电力电子的一些知识

文章目录数电模电逻辑电路与或非异或 门电路与的物理电路边沿触发器功率交流容量直流容量桥电路CHBDABTHD电路器件LM7815与LM7915数电模电 逻辑电路 与或非异或 门电路 与乘大于1或加大于1异或异性为1&#xff0c;异吗&#xff1f; 与的物理电路 当二极管是高电平&#xf…