一篇搞定Spring,IOC容器,Bean管理,3.AOP底层原理和实现(收下吧,真的很详细)

news2024/12/26 23:22:10

1.Spring容器的概念

Spring是一个轻量级的框架,可以解决企业开发的复杂性,让开发效率提升,他核心的两个点是:

1.IOC

IOC:在java中,我们程序员一般是去创建一个对象,那么有个问题就是耦合性太高了,在后期的修改和维护的维修成本比较大,在IOC中,对象的创建依赖注入是由容器负责,而不是由程序员直接控制,他是通过dl的注入方式,来实现对象直接的解耦,提高了代码的灵活性和可维护性

2.AOP

AOP:AOP也被称为面向切面,他可以在不改变原代码对功能进行增强

1.2,Spring入门

首先我们要在pom.xml中添加spring的依赖

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.24</version>
        </dependency>


        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.24</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
<!--            <scope>test</scope>-->
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.23</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>



    </dependencies>

在这里我添加了mysql的依赖,大家也可以先添加上去,在后面我们的案例中会用到,如果下载失败或者网络原因下载中断,或者还不会配置maven的可以参考我之前写的

https://blog.csdn.net/m0_70812512/article/details/139581648?spm=1001.2014.3001.5502

在这里就会有你spring的依赖项

如果说你去创建xml没有这个图标说明你spring依赖没有配置好。

好接下来我们通过几个案例来了解到这个spring注入的方式

1.通过xml实现注入

通过我们去拿取这个对象中的方法时都是去创建他,这个会很繁琐,而且后期维护性也不高

那么我们就可以通过spring将对象交给spring去管理,让spring帮我们去注入

1.set注入

首先看这里,在这里我们创建了一个user类,在这个类中我修饰了一个name,并且为这个name提供了一个set方法,用于注入值,并且提供了一个构造函数,那么他现在是符合springbean注入的条件

现在我通过xml来注入,我们定义了一个bean的标签,并且指定了他所以管理的对象是User,在property中我们指定了User中的属性名name,并且为name赋值

现在我们来测试看看会是什么结果

//        加载自定义的spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("beans2.xml");
// 获取配置文件对象User
        User user = context.getBean("user",User.class);
// 操作user对象
//        System.out.println(user);
        user.add();

在这里我们可以看到,我们告诉了spring是那一个配置文件,那他就会根据你配置文件中所定义的bean去构造这个对象,在通过getbean获取到这个对象(我们给每个bean都设置了id),并且调用其中的方法,这样就不在是我们程序员手动创建对象了,而是交给spring管理,让他帮我们来管理这个对象

<!--    属性注入方式-->
    <bean id="user2" class="com.zking.Utile.User">
        <property name="name" value="谭建涛"></property>
    </bean>

    <!--    构造注入方式-->
    <bean id="user3" class="com.zking.Utile.User">
        <constructor-arg name="name" value="有参构造注入方式"></constructor-arg>
    </bean>

    <!--    p注入方式-->
    <bean id="user4" class="com.zking.Utile.User"  p:name="p注入方式">

    </bean>

当然这里还有一些其他的注入方式大家也可以去试试,在这里我们就不全部展示出来了,他们的意思都一样,就是通过springIOC来管理这个创建对象的过程,我们去拿就行

接下来我们来按照我们经常写代码的一些主要配置来搞几个小案例

 我们看这里,我有一个数据访问层和一个业务逻辑层,在业务逻辑层中构造了数据访问层的这个对象,并且里面提供了一个

User_Sevsiver

方法,在这个方中可以去直接实现我们UserDao中的执行语句

好,现在我们来看xml,我将Userdao和UserServer都交给spring管理,并且设置了一个不同的id

在UserServier中就会去注入这个UserDao(上面id是UserDao),那既然我们已经注入了UserDao在这个set方法中了,那我在去调UserServier中的

User_Sevsiver

方法,他不就是会去执行到UserDao中的方法吗

实现了吧,是吧,其他案例我就不一一写了,基本都都大差不差,其实就是原来我们要直接去创建对象,现在不用了,给spring去管理,我们拿就好了,spring通过dl注入实现IOC控制反转

在说一个吧,spring自动装配

在这里我们将UserDao和UserSever交给spring管理,并且在 后面我们添加了autowire="byName",这个的意思是springIOC中的一个自动装配的一方式,他会扫描ImpUserServer中的属性值,比如说是userdao,那么他就会尝试将userdao注入到usersever这个bean当中,就可以实现spring的自动装配

1.3.通过组件扫描的方式实现

虽然说这种xml声明的方式确实可以实现我们的IOC控制反转,但是这个步骤什么的到处配置还是会有点麻烦,那么spring肯定还有其他的方式来实现这个控制反转,那就是组件扫描

1.什么是组件扫描

我们来看这个张图,我们原来是不是声明告诉spring,我指定那些要注入的东西那我们在根据他这个id去调这个bean,就可以实现这个方法了吧。

那有没有一种方式就是说,我可以给每一个对象中去声明一个标识符,在让spring通过标识符来识别变成一个bean,并且扫描不是指定某一个类来实现,而是去扫描结构下的所以类,当然有,我们来看上面的图片,我们指定开起了组件扫描,扫描com.zking下面的所以类

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

    <!--    开启组件扫描,当前扫描com.zking下的全部组件-->
    <!--    <context:component-scan base-package="com.zking"></context:component-scan>-->
    <!--    是 Spring 的注解驱动配置之一,用于自动扫描指定包下的组件,-->
    <!--    如带有 @Component, @Repository, @Service, @Controller 等注解的类,并将其注册为 Spring 的 Bean。-->

    <context:component-scan base-package="com.zking"></context:component-scan>



</beans>

这里的

 @Component, @Repository, @Service, @Controller 

就是我们今天要说的通过注解的方式实现DL注入

首先我们先来了解这是是什么,首先要知道spring就是通过识别出com.zking下面的所以包含这些注解的来作为spring的bean,那有了这个bean,他就可以通过这个bean去里面拿这个对象去实现这个方法。

@Component:是spring当中的一个注解,他一般是拥有业务逻辑层,你可以理解为他将自己变成了一个spring可以扫描识别到变成一个bean

@Repository:一般用于数据访问层,他就是告诉spring我这个类是用于数据访问的

@Service:一看名字就知道了吧,他其实就是告诉spring他是业务逻辑层

@Controller:这个注解标记的类是一个 Spring MVC 控制器组件,用于处理 HTTP 请求和响应。它扩展了 @Component 注解,通常与 Spring MVC 框架结合使用,用于构建 Web 应用。

他们都可以和@Autowired 或 @Resource 等注解来自动装配 Bean

@Autowired:是spring的自动注解,我们声明的全局变量中

在这里我们创建了一个ImpUser_Dao类,并且将他标记为
@Repository("userDao")spring中的组件,这里这个的意思是为相当于注入对象的name属性,可以理解为id,默认是这个类小写,impUser_Dao,那么在 ImpUserSever_Dao 中,我们设置为自动注入@Autowired,在UserDao userDao = null;userdao要和你那个dao里面的@Repository("userDao")值一致,因为他是通过你这个name的属性值在com.zking下去扫描,去找,找到了就将这个对象注入进去,在最后我们就可以通过
UserSever serv = apl.getBean("impUserSever_Dao",UserSever.class);

去创建这个类并且调用他里面的方法(默认是首字母小写),那么他就会自动的将Userdao注入进去,我们在调里面的方法是也就可以执行到数据访问逻辑层中了

那么这种其实还是依赖了xml,如果不想依赖xml,完全注解开发

package com.zking.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

//标记当前类为配置类
@Configuration
// 开启组件扫描
@ComponentScan({"com.zking"})
//引入外部配置文件
@PropertySource("db.properties")
public class SpringUserConfig {
}

我们可以通过创建一个java类,在类中将他声明为他是配置文件

在通过 

ApplicationContext apl = new AnnotationConfigApplicationContext(SpringUserConfig.class);

作引入,是相同的效果。

3.AOP底层原理和实现

1.AOP是什么

简单来说aop就说在不改变原代码时,对原来的功能增强

AOP也被称为面向切面,切面的意思是为他是由我们定义的切点组成的,可以理解为我现在有两个类,一个userdao,一个Studentdao,他们下面分别有add,update方法,那么他们类里面的方法又可以叫切点,那么我们就可以定义这个切点为一个切面,对我们的功能代码增强。 

2.AOP的底层原理

 就是动态代理,动态代理又可以分为

有接口的情况:JDK动态代理

无接口情况:CGLIB动态代理

1.有接口的情况:JDK动态代理

package com.zking.dao.imp;

import com.zking.dao.UserDao;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;

@Repository
public class ImpUserDao implements UserDao {

    @Override


    public void add() {
        System.out.println("数据添加");
    }

    @Override
    public void Update() {
        System.out.println("数据修改");
    }
}

创建Userdao接口代理对象

 2.无接口情况:CGLIB动态代理

package com.zking.proxy.CGilb;

public class User {
    public void add(){
        System.out.println("CGLIB方式");
    }
    public static class person extends User{
        public void add(){
            System.out.println("CGLIB开启事务");
            super.add();
            System.out.println("CGLIB事务提交");
        }
    }

}

没有接口,而是直接继承这个类中的方法在方法之前作增强

java动态代理

package com.zking.proxy;

import com.zking.dao.UserDao;

/**
 * 用户Dao代理类,用于在不修改原有UserDao实现的基础上,添加额外的功能(如日志、事务等)。
 */
public class UserDaoproxy2 {

    private UserDao userDao;

    /**
     * 构造函数,传入UserDao实例,代理类将围绕这个实例进行操作。
     * 
     * @param userDao 需要被代理的UserDao实例
     */
    public UserDaoproxy2(UserDao userdao) {
        this.userDao = userdao;
    }

    /**
     * 创建UserDao的代理实例。
     * 
     * @return 返回代理后的UserDao实例
     */
    public UserDao newProxyInstance() {
        System.out.println("代理类");
        // 使用Java反射机制创建代理实例,代理实现类为UserInvoaction
        return (UserDao) java.lang.reflect.Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), new UserInvoaction());
    }

    /**
     * InvocationHandler实现类,用于处理代理对象的方法调用。
     */
    class UserInvoaction implements java.lang.reflect.InvocationHandler {
        /**
         * 当调用代理对象的方法时,实际上会执行此方法。
         * 
         * @param proxy 代理对象
         * @param method 被调用的方法
         * @param args 方法参数
         * @return 方法返回值
         * @throws Throwable 方法执行中抛出的异常
         */
        public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable {
            System.out.println("前置增强");
            // 调用原始UserDao实例的方法
            Object obj = method.invoke(userDao, args);
            System.out.println("后置增强");
            // 返回方法执行结果
            return obj;
        }
    }
}

4.AOP准备工作

Aspectl介绍

在spring当中一般都在基于Aspectl实现aop操作的,Aspectl不是spring的一部分,而且是一个独立的AOP框架,一般把Aspectl和Spring一起使用,进行AOP操作,因为这样更方便

基于Aspectl进行AOP 操作的方式有两种

1.基于xml配置文件的方式实现

2.基于注解的方式实现

基于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"
       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
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
        ">

    <!--    开启组件扫描,当前扫描com.zking下的全部组件-->
    <!--    <context:component-scan base-package="com.zking"></context:component-scan>-->
    <!--    是 Spring 的注解驱动配置之一,用于自动扫描指定包下的组件,-->
    <!--    如带有 @Component, @Repository, @Service, @Controller 等注解的类,并将其注册为 Spring 的 Bean。-->

    <context:component-scan base-package="com.zking"></context:component-scan>
<!--    <context:component-scan base-package="com.zking">-->
<!--        <context:exclude-filter type="assignable" expression="com.zking.aop.LogAspect"/>-->
<!--    </context:component-scan>-->

<!--    开启aspectl生成代理对象-->
<!--    roxy-target-class="true"代理目标可以是类,默认为接口-->
    <aop:aspectj-autoproxy/>

</beans>

首先我们在xml中开启组件扫描,扫描com.zking下面的所以类,并且开启aspectl生成代理对象

 

现在我有一个UserServerImp的类,类中有这些方法

package com.zking.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.management.DescriptorKey;

//@Aspect : 表明当前类是增强类
@Aspect
@Order(1)
@Component
public class LogAspect {
//    设置切点
//@Pointcut("execution(* com.zking.dao..*.*(..))")
@Pointcut("execution(* com.zking..*.*(..))")
public void pointcut(){

}

    @Before("pointcut()")

    public void before() {
        System.out.println("UserSeverimp前置通知");
    }
    @After("pointcut()")
    public void after(){
        System.out.println("UserSeverimp后置通知");
    }
    @AfterReturning("pointcut()")
    public void afterReturning(){
        System.out.println("UserSeverimp返回通知");
    }
    @AfterThrowing("pointcut()")
    public void afterThrowing(){
        System.out.println("UserSeverimp异常通知");
    }
    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable{
//        System.out.println("UserSeverimp环绕通知");
        joinPoint.proceed();
        System.out.println("UserSeverimp环绕通知");
    }

}

并且又创建了一个类,@Aspect : 表明当前类是增强类,

@Pointcut("execution(* com.zking..*.*(..))")

这个帮忙当前com.zking下面所以类中所以的方法,属性为任意类型,这样就组成了一个切面,切面下面有各种各样方方法,那么在执行程序时就会去扫描,看那些增强类,然后对类实现增强功能,

 

可以看到,本来我应该只是会输出用户添加的,但是因为我们配置了AOP,他就会在我们代码执行之前先执行我们增强类中的方法。好了,今天就到这里啦,累了兄弟们。

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

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

相关文章

Apache DolphinScheduler查看版本信息

我找了半天&#xff0c;没有看到版本在哪里。然后我看配置&#xff0c;他要连接数据库&#xff0c;我去他存储数据库的表里面&#xff0c;看到了相关的版本信息。 cd /home/dolphinscheduler/dolphinscheduler/bin/env dolphinscheduler找到了里面的密码 版本是3.1.3

VMware挂载NAS存储异常处理

问题概述 由于非法关机或恢复&#xff0c;NFS存储可能会出现以下问题&#xff1a; 数据存储处于挂起状态或无法正常识别。虚拟机的配置文件或虚拟磁盘仍然注册在异常数据存储上。系统误认为有虚拟机在使用该数据存储。 问题对策 下面是详细的排查步骤和解决对策&#xff1a…

JS 实现Date日期格式的本地化

为了更好的更新多语言日期的显示&#xff0c;所以希望实现日期的本地化格式显示要求&#xff0c;常规的特殊字符型格式化无法满足显示要求&#xff0c;这里整理了几种我思考实现的本地化实现功能。 通过多方查找&#xff0c;总结了实现的思路主要有如下三个方向&#xff1a; 官…

ThinkPHP 的老漏洞仍然被攻击者钟情

研究人员发现安全领域出现了令人不安的趋势&#xff1a;攻击者不仅对新披露的漏洞十分感兴趣&#xff0c;对已知的漏洞也丝毫不放过&#xff0c;尽管有些漏洞已经存在了好些年头&#xff0c;攻击者仍然能够通过老漏洞成功完成攻击。 典型的例子就是 ThinkPHP 远程代码执行漏洞…

同三维T80004EHL-W-4K30 4K HDMI编码器,支持WEBRTC协议

输入&#xff1a;1路HDMI1路3.5音频&#xff0c;1路HDMI环出1路3.5音频解嵌输出 4K30超高清,支持U盘/移动硬盘/TF卡录制&#xff0c;支持WEBRTC协议&#xff0c;超低延时&#xff0c;支持3个点外网访问 1个主流1个副流输出&#xff0c;可定制选配POE供电模块&#xff0c;WEBR…

白酒:茅台镇白酒的文化内涵与传承意义

茅台镇白酒&#xff0c;作为中国的酒文化的代表之一&#xff0c;具有丰富的文化内涵和传承意义。而云仓酒庄豪迈白酒作为茅台镇的品牌之一&#xff0c;更是承载了深厚的文化底蕴和历史积淀。 首先&#xff0c;茅台镇白酒是中国的酒文化的重要组成部分。白酒在中国有着悠久的历史…

SRAM和DRAM

1.SRAM&#xff08;静态RAM&#xff09; 把存放一个二进制位的物理器件称为存储元&#xff0c;它是存储器最基本的构件。 地址码相同的多个存储元构成一个存储单元。 存储单元的集合构成存储体。 静态RAM的存储元是用双稳态触发器&#xff08;六晶体管MOS&#xff09;来记忆…

MyBatis查询两个字段,返回Map,一个字段作为key,一个字段作为value的实现

项目场景&#xff1a; 在使用MyBatis&#xff0c;我们经常会遇到这种情况&#xff1a;SELECT两个字段&#xff0c;需要返回一个Map&#xff0c;其中第一个字段作为key&#xff0c;第二个字段作为value。MyBatis的MapKey虽然很实用&#xff0c;但并不能解决这种场景。 问题描述 …

vue分类

先看效果 再看代码 <category-tab v-model"params.area" name"地区" :list"areaList" /><category-tab v-model"params.type" name"类型" :list"typeList" /><category-tab v-model"params.…

WPF/C#:如何将数据分组显示

WPF Samples中的示例 在WPF Samples中有一个关于Grouping的Demo。 该Demo结构如下&#xff1a; MainWindow.xaml如下&#xff1a; <Window x:Class"Grouping.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x&q…

【面试 - 页面优化举例】页面跳转卡顿问题解决 - 页面跳转速度优化

目录 为何要优化如何优化优化1 - 懒加载优化2 - el-tree 子节点默认不展开 为何要优化 页面A跳转到也页面B时&#xff0c;页面出现卡顿情况&#xff1a; 【问题】页面A → 页面B时&#xff0c;页面B进入到了 created 钩子后过了六七秒才进入到 mounted 钩子&#xff1b;【分析经…

vue分页

先看效果 再看代码 <!-- 分页 --><div v-if"pageParams.pageCount > 1" class"flex justify-end mt-6"><n-paginationv-model:page"pageParams.page" v-model:page-size"pageParams.pageSize" :page-count"pa…

生产 的mybatisplus 日志输入到日志文件

默认是输出到控制台.不输出到日志文件 输出到日志文件.需要修改配置 第一步. logging:config: classpath:logback-wshoto.xml第二步 mybatis-plus:configuration:cache-enabled: truedefault-executor-type: reuselog-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl第三步…

标准立项 | 膜曝气生物膜反应器(MABR)平板曝气膜

立项单位&#xff1a;天津市华宇膜技术有限公司、中国市政工程中南设计研究总院有限公司、中建生态环境集团有限公司、富朗世水务技术(江苏)有限公司、常州宣清环境科技有限公司 膜组件开发 膜腔内部支撑结构-一在膜腔内部设置支撑结构以防止膜腔在水压下压实&#xff0c;同时…

CRMEB多门店的门店后台首页路由

如何在输入 http://localhost:8080/、http://localhost:8080/store/、http://localhost:8080/custom-store/ 这三个中任意一个链接都能正确跳转到 http://localhost:8080/store/home/index 。要实这个要求&#xff0c;有两种方式&#xff1a; 重定向 const router new VueRo…

WPF/C#:更改界面的样式

项目结构&#xff1a; 先来看看BlueSkin.xaml与YellowSkin.xaml。 BlueSkin.xaml&#xff1a; <ResourceDictionaryxmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:l…

SVN代码无法提交(报错lock)

SVN无法commit(可以导出可以update)报错画面如下&#xff1a; 报错&#xff1a;If you want to break the lock, use the check For Modifcations dialoo or the repository browser. 前提&#xff1a;使用解锁和clean up无效 解决办法&#xff1a;导出报错仓库数据到本地&am…

9种编程语言的对比分析

在当今的软件开发领域&#xff0c;编程语言扮演着至关重要的角色。不同的编程语言各有其特点和适用场景&#xff0c;选择合适的编程语言能够提高开发效率和软件质量。本文将对十种常见的编程语言进行对比分析&#xff0c;帮助读者了解它们的优缺点和适用场景。 Java 特点&…

Springboot微服务整合缓存的时候报循环依赖的错误 两种解决方案

错误再现 Error starting ApplicationContext. To display the conditions report re-run your application with debug enabled. 2024-06-17 16:52:41.008 ERROR 20544 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPLI…

git将代码提交到github

第一次代码提交 1.在github新建一个空白仓库 2、当前在文件下 3、git init 5、git add .(当前目录下所有代码全部提交) 6、git commit -n "init" 这次提交的备注信息 7、git branch -M main 8、git remote add origin (address) 9、git push -u origin main 第…