spring面试题总结

news2024/10/2 12:33:21

1、spring是什么?

 

spring是一个轻量级IOC和AOP容器框架,是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用的开发,开发者只需要关注业务需求即可:

  •  core container 容器组件
    • spring context,容器上下文
    • spring core  核心类库,所有功能都依赖该类库,提供IOC和DI服务
    • spring beans 进行实例的管理
  • spring AOP 提供AOP服务
  • spring web -- 实际就是MVC框架,spring提供了面向web的综合特性,提供了对常见web框架的支持,spring可以管理这些框架,并将spring的资源注入给框架,也可以在框架的前后插入拦截器。
  • data acess --- spring的数据访问组件,帮助完成事务管理及持久化操作(没有mybatis也可以完成持久化操作)
  • test   --- 单元测试组件

2 spring 的优点?

  1. 基于POJO的轻量级和最小侵入性编程
  2. 通过依赖注入和面向接口,减低了组件的耦合性
  3. 提供了AOP技术,支持将一些通用的任务,如安全,日志,事务等进行集中管理,从而实现更好的代码复用
  4. spring对主流的应用框架提供了集成支持

3、spring框架中都用到了哪些涉及模式?

  1. 工厂模式: BeanFactory 简单工厂模式,用来创建对象
  2. 单例模式:spring创建出来的bean默认就是单例模式
  3. 代理模式:spring的aop功能用到了动态代理技术(jdk、CGLib)
  4. 模板方法:解决代码重复问题,比如 RestTemplate, JmsTemplate, JpaTemplate
  5. 观察者模式:定义对象键,一种一对多的依赖关系,当一个对象状态发生改变时,所有依赖他的对象都会得到通知被动刷新,如spring中listener的实现 ---ApplicationListener

4、spring框架中有哪些不同类型的事件?

spring提供了一些5种标准的事件:

  1. 上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
  2. 上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
  3. 上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
  4. 上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
  5. 请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。

5 、spring 的IOC?

5.1、什么是IOC?

        IOC,inversion of control,控制反转,将对象的控制权转移给spring框架进行管理,由spring来控制对象的生命周期(创建,销毁)和对象之间的依赖关系。

也就是说,以前创建对象的时机和主动权是由开发者把握的,如果在一个对象中使用外面的对象,就需要new去创建对象,用完后还涉及到对象的销毁,这种情况下,当前对象就会和其他的接口或者类耦合起来。而IOC则是由专门的容器去创建对象,我们只需要将所有的类在spring中进行登记,当需要某个对象时,只需要告诉spring容器,然后spring就会在适当的时机,把想要的对象主动给我们。也就是说,IOC中,所有的容器都被spring控制,spring容器帮我们创建,查找,注入依赖对象。

5.2 、什么是DI 

        DI ,dependency injection 依赖注入,在spring完成对象创建的同时,完成对象属性的赋值。这个行为是动态的。

        容器全权负责依赖的查询,受管组件只需要暴露JavaBean的setter方法或者带参数构造器,容器就可以在初始化的时候组装对象的依赖关系。

依赖注入的实现方式?

  • 接口注入(不用)
  • setter方法注入 --- bean标签中通过property标签的value属性进行赋值(实际就是通过反射调用set方法完成属性输入)
  • 构造器注入 ---  Java类中定义带参数构造器,<constructor-arg index="0" value="10001"/> ,index是参数的位置

两种依赖方式都可以使用,一般来说,自己定义的类,用setter注入比较多,第三方的技术整合时,构造器注入用的比较多。

5.3 、IOC的原理

        spring ioc的实现原理就是工厂模式加反射。简单实例代码如下 

        Class.forName(ClassName).newInstance();

interface Fruit {
   public abstract void eat();
 }
 
class Apple implements Fruit {
    public void eat(){
        System.out.println("Apple");
    }
}
 
class Orange implements Fruit {
    public void eat(){
        System.out.println("Orange");
    }
}
 
class Factory {
    public static Fruit getInstance(String ClassName) {
        Fruit f=null;
        try {
            f=(Fruit)Class.forName(ClassName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}
 
class Client {
    public static void main(String[] a) {
        Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple");
        if(f!=null){
            f.eat();
        }
    }
}

5.4、 IOC的作用?

  • 管理对象的创建和依赖的维护
  • 解耦,由容器去维护具体的对象
  • 托管类的生产过程,如通过代理在类的生产过程中做一些处理,交给容器去做。

5.5 、spring的IoC支持哪些功能?

  • 依赖注入DI --- 最重要的功能,从XML的配置上说,就是ref标签,对应着spring的RuntimeBeanRefrence对象。
  • 依赖检查
  • 自动装配
  • 指定初始化和销毁方法
  • 支持回调某些方法

6、BeanFactory和ApplicationContext有什么区别?

BeanFactory和ApplicationContext是spring的两大核心接口,都可以当做spring的容器,其中ApplicationContext是BeanFactory的子接口。

依赖关系:

BeanFactory:是spring中最底层的接口,包含了各种bean的定义,读取bean配置文档,管理bean的加载,实例化,控制bean的生命周期,维护bean之间的依赖关系。

ApplicationContext是BeanFactory的子接口,除了提供BeanFactory所有的功能外,还提供了更完整的框架功能(其他继承接口的功能),如支持国际化(继承MessageSource)、统一的资源文件访问方式,提供在监听器中注册bean的事件,同时加载多个配置文件等。

加载方式:

BeanFactory采用的是延迟加载形式来注入Bean,因此只有在使用到某个Bean时(调用getBean()方法),才会该Bean进行加载实例化,这样如果存在配置问题,不容易第一时间发现

ApplicationContext是在容器启动的时候,一次性创建所有的Bean, 这样在容器启动过程中就可以发现Spring中的配置错误,有利于检查依赖是否注入。不足是占用内存空间,但在是也可以定义成延迟加载,bean的元数据中定义 lazy-init=“true”

7、spring是如何设计容器的,BeanFactory和ApplicationContext关系详解

BeanFactory 可以称为“低级容器”,底层是个HashMap, key是BeanName,value是Bean的实例,通常只提供注册(put),和获取(get)功能。

ApplicationContext可以称为“高级容器”,他继承了多个接口,因此具备了更多的功能,这个接口定义了一个refresh方法,用于刷新整个容器,即重新加载所有的bean。

IoC在spring中,其实只需要低级容器就可以实现,两个步骤如下:

1、加载配置文件,解析成BeanDefinition放在Map中;

2、调用getBean的时候,从BeanDefinition所属的Map中,拿出Class对象进行实例化,如果有依赖关系,则递归调用getBean方法,完成依赖注入。

至于高级容器ApplicationContext,包含了上述功能,同时支持不同的信息源头,支持访问文件资源,支持事件发布通知,支持接口回调等等功能。

8、ApplicationContext通常的实现有哪些?

FileSystemXmlApplicationContext: 从一个xml文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。---常用于配置文件在文件系统路径下

ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。--- 常用于配置文件在类路径下。

WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。

AnnotationConfigApplicationContext:基于注解加载bean,避免使用application.xml进行配置。相比XML配置,更加便捷。

9、什么是spring beans?

在spring中,构成应用程序主干并由spring IOC管理的对象称为bean,或者说是被Spring IoC容器初始化,装配和管理的Java对象,这些beans通过容器配置的元数据创建。

bean相关的元数据

<bean
    id="bookDao"   ----bean的id
    name="dao"     ----bean的别名
    class="com.itheima.dao.BookDaoImpl"     ----bean的类型,全路径名
    scope="singleton"    ----控制bean的实例数量,默认是singleton单例,prototype是多例bean
    init-method="init"        ---- bean生命周期的初始化方法
    destory-method="destory"        ----bean生命周期的销毁方法,销毁前运行的方法
    autowire="byType"        ----自动装配类型
    factory-method="getInstance"        ----bean的工厂方法,应用于静态工厂或者实例工厂
    factory-bean="com.itheima.factory.BookDaoFactory"         ----实例工厂bean
    lazy-init="true"    ----控制bean的延迟加载,默认是false
/>

 

依赖注入相关的元数据

<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
    <constructor-arg name="bookDao" ref="bookDao"/>
    <constructor-arg name="userDao" ref="userDao"/>
    <property name="bookDao" ref="bookDao"/>
</bean>

10、怎么定义类的作用域?spring支持哪几种作用域?

spring中,可以通过bean定义中的scope属性来定义bean 的作用域,spring中默认的作用域是singleton,表示单例模式。

spring中支持bean的几种作用域如下

  1. singleton 单例bean,在每个spring IOC 容器中只有一个实例
  2. prototype:多例bean,一个bean的定义有多个实例,相当于new ---频繁的创建和销毁bean会带来比较大的开销,需要注意。
  3. request:每次http请求都会创建一个bean,该作用域仅在基于web的spring ApplicationContext情况下有效
  4. session:在一个http session中,一个bean对应一个实例,该作用域仅在基于web的spring ApplicationContext情况下有效
  5. global-session: 在一个全局的http session中,一个bean对应一个实例,该作用域仅在基于web的spring ApplicationContext情况下有效

11、spring框架中单例bean是线程安全的吗?

不是,单例bean不是线程安全的,spring框架并没有对单例bean进行多线程的封装处理

实际上,大部分的时候,spring 中的bean都是无状态的(比如dao类,不保存数据),这种bean就无所谓线程安全了,而针对有状态的bean(view,model对象),就需要开发者自己去保证线程安全了。

解决办法:

  • 使用prototype,改变bean的作用域
  • 使用ThredLocal,将成员变量放在ThredLocal里面,传进来的参数都是跟随线程的,因此也是线程安全的 ---- ThredLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突,属于空间换时间
  • 使用同步锁 synchronized ,属于时间换空间的办法,会影响吞吐量。

12、Spring bean 的生命周期

1、加载bean的定义

        通过loadBeanDefinitions扫描所有xml配置,注解等将bean 记录在 beanDefinitionMap中

2、创建bean对象

        通过doCreateBean()遍历beanDefinitionMap 来创建bean

        2.1 构建对象

                容器通过createBeanInstance()进行对象的构造(获取构造方法,首先是加了@Autowired注解的构方法,其次是无参构造方法、、、如果存在多个构造方法spring难以识别,则会抛出异常)

                准备参数(构造器的入参) 首先是根据类型进行查找,其次通过参数名查找

                构造对象,对于无参对象,则直接实例化,有参数的则进行属性的填充

        2.2 属性填充

                通过populateBean()方法为bean内部的属性进行赋值,通常是@Autowired注解的变量

        2.3 初始化bean对象

                通过initializeBean()方法对填充后的实例进行初始化

                第一步是初始化容器相关信息,通过invokAwareMethods()方法,为实现了aware接口(信息感知接口)的bean设置注入 beanName,beanFactory等容器相关信息

                第二步是执行bean的初始化方法,通过invokeInitMethods()方法进行初始化-------如果Bean实现了InitializingBean接口,则会调用他的afterPropertiesSet()方法,同样的,如果用户自定义了init-method方法,那么也会执行 

                如果Bean实现了BeanPostProcessors接口【bean后置处理器】,则会在初始化方法invokeInitMethods()前后分别执行 postProcessBeforeInitialization()和postProcessAfterInitialization() 方法,此时,bean已经准备就绪,可以被应用程序使用了

                如果bean实现了DisposableBean接口,spring会调用他的destory()方法。

        2.4 添加到单例池

                如果bean被声明为singleton,则会被加入单例池,由spring进行管理。

3. 销毁

        销毁前,调用bean中@PreDestroy注解 的方法,

        然后通过postProcessBeforeDestruction方法调用destoryBean逐一销毁Bean

        调用 invokeCustomDestoryMethod执行客户自定义的销毁。

13. 声明是Spring的内部bean? spring inner beans?

当一个bean仅被用作另一个bean的属性时,能被声明为一个内部bean,内部bean可以用setter注入属性 和 构造方法注入构造参数的方法来实现,内部bean通常是匿名的,scope一般是prototype。

14 spring中如何注入一个集合?

<list>类型用于注入一列值,允许有相同的值。

<set> 类型用于注入一组值,不允许有相同的值。

<map> 类型用于注入一组键值对,键和值都可以为任意类型。

<props>类型用于注入一组键值对,键和值都只能为String类型。

15、什么是bean装配?什么是bean的自动装配?

bean的装配就是指在spring容器中,把bean组装到一起,前提是知道bean的依赖关系,通过依赖注入把他们装配到一起。

自动装配就是Spring容器能够自动装配相互合作的bean,通过beanFactory自动处理bean之间的协作

XML里面配置自动装配方式 autowire属性:

  • no:默认的方式是不进行自动装配的,而是通过手工配置ref属性来指定要装配的bean
  • byName: 通过bean的名称进行自动装配,如果一个bean的property属性和另一个bean的name(id)相同,则进行自动装配
  • byType:通过参数的数据类型进行自动装配
  • constructor:利用构造函数进行装配,并且构造函数的参数通过bytype进行装配
  • autodetect: 自动探测,有构造方法,则通过构造方法,没有则根据byType

@Autowired注解:

启动spring的IOC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。

  • 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
  • 如果查询的结果不止一个,那么@Autowired会根据名称来查找;
  • 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

16、 自动装配有哪些局限性?

基本数据类型和string字符串不能自动装配

自动装配不如显式装配精确。

17 什么是基于注解的配置?

允许在少量Java注解的帮助下,进行大部分spring的配置,而不是xml文件

如,@Configuration声明配置这是一个配置类,然后在这个类中使用@Bean注解,定义bean

@Configuration
public class StudentConfig {
    @Bean
    public StudentBean myStudent() {
        return new StudentBean();
    }
}

 18 怎么开启注解装配

注解装配默认是关闭的,如果想使用,则需要在spring的配置文件中配置

<!-- 声明使用注解配置 -->
<context:annotation-config/>

<!-- 声明Spring工厂注解的扫描范围 -->
<context:component-scan base-package="com.qfedu.beans"/>
  • @Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
  • @Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。
  • @Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。
  • @Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。

19  @Required 注解有什么用?

这个注解表明bean的属性必须在配置的时候进行设置值,如果未设置,则会抛出BeanInitializationException异常。

20 @Autowired注解和@Resource注解之间的区别?

都是属性注解, @Autowired还可以用作set方法上

  • @Autowired  按照类型进行装配,默认情况要求依赖对象必须要存在(可以设置required属性为false)
  • @Resource  按照名称进行装配,找不到名称才会按照类型装配

21  @Qualifier注解作用?

当创建多个相同类型的bean时,并希望仅仅使用属性进行装配其中一个bean时,可以使用@Qualifier 注解进行指定,通常和@Autowired注解一起使用在setter方法

@Autowired
public void setClazz(@Qualifier("c2") Clazz clazz) {
    this.clazz = clazz;
}

22 spring 支持的事务管理类型?

spring事务的本质其实是对数据库事务的支持。

  • 编程式事务管理,在代码中显示调用开启事务,提交事务,回滚事务的相关方法。优点是灵活性高,但是难以维护
  • 声明式事务管理,底层建立在AOP基础上,本质是对方法的前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在方法执行完之后,根据执行情况提交或者回滚事务。----从业务代码里面分离出事务管理,仅仅用注解或者xml来配置管理事务

大多数Spring框架的用户选择声明式事务管理,因为它对应用代码的影响最小,因此更符合一个无侵入的轻量级容器的思想。声明式事务管理要优于编程式事务管理,虽然比编程式事务管理(这种方式允许你通过代码控制事务)少了一点灵活性。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。
 

23 spring 事务隔离级别

spring中有五大隔离级别,默认值是isolation_default(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致,读未提交,读已提交,可重复读,串行化。

24 spring 的事务传播行为

事务的传播行为,指的是当多个事务同事存在的时候,spring如何处理这些事务。

  1. PROPAGATION_REQUIRED:如果没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,是最常见的设置
  2. PROPAGATION_SUPPORTS:支持当前事务,如果存在事务,就加入该事务,如果当前不存在事务,则以非事务执行
  3. PROPAGATION_MANDATORY:强制事务,如果当前存在事务,则加入该事务,如果不存在,则抛出异常
  4. PROPAGATION_REQUIRES_NEW:创建新的事务,不管当前是否存在事务
  5. PROPAGATION_NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则将事务挂起
  6. PROPAGATION_NEVER:以非事务执行,如果当前存在事务,则抛出异常
  7. PROPAGATION_NESTED:嵌套事务,如果不存在事务,则创建事务,如果存在事务,则创建一个新事务,嵌套到当前事务中。

 25 spring框架的事务管理有哪些优点?

为不同的事务API提供了一个不变的编程模式(JDBC/JTA等)

为编程式事务管理提供了一套简单的API

支持声明式事务管理,易于管理,对代码侵入性小

和spring各种数据访问抽象层很好的集成。

26 什么是AOP?

Aspect - Oriented Programming ,面向切面编程。是一种通过动态代理,对原有的业务逻辑进行拦截,并且在这个拦截的横切面上添加特点的处理逻辑,实现对原有业务的增强。

连接点(jointPoint): 程序中的方法

切入点(pointCut): 被spring横切的方法

通知/增强(Advice):定义切点放在切入点的前面、后面,还是哪里。。。

切点: 添加到切入点的方法(如事务的begin,commit,rollback)

切面:定义切点方法的类

织入(weaving): 就是把切面应用到目标对象,并创建新的代理对象的过程。

27 spring 中的通知都有哪些类型?

AOP中,切面的工作被称为通知,实际上是程序执行时要通过springAOP框架触发的代码段。

spring切面可以配置以下5种类型的通知:

  1. 前置通知 before:在目标方法调用之前调用通知功能
  2. 后置通知 after: 在目标方法完成之后调用通知,不会关心方法输出什么
  3. 返回通知 After-returning: 在目标方法成功之后调用通知
  4. 异常通知 After-throwing:在目标方法异常之后调用
  5. 环绕通知around:通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义行为。

after 和 after-returning根据配置的顺序决定执行顺序

28、代理模式,动态代理?

代理模式的优点:将通用性的工作交给代理对象完成,而被代理对象只需要专注自己的核心业务即可。减少代码耦合。

动态代理,几乎可以为所有的类产生代理对象,无需声明式的创建Java代理类,在运行过程中生成虚拟的代理类,被classLoader加载。动态代理的实现方式有两种:JDK动态代理和CGLib动态代理。

28.1 JDK动态代理:

通过被代理对象实现的接口产生代理对象的:

  1. 创建一个类,实现InvocationHandler接口,重写invoke方法 ---method.invoke(obj,args); 这个就是通过反射执行被代理类的方法。
  2. 在类中定义一个Object类型变量,并提供这个变量的有参数构造器,用于把代理对象传递进来
  3. 定义getProxy()方法,用于创建并返回代理对象。
public class JDKDynamicProxy implements InvocationHandler {
    //被代理对象
    private Object obj;
    public JDKDynamicProxy(Object obj) {
        this.obj = obj;
    }
    //产生代理对象,返回代理对象
    public Object getProxy(){
        //1.获取被代理对象的类加载器
        ClassLoader classLoader = obj.getClass().getClassLoader();
        //2.获取被代理对象的类实现的接口
        Class<?>[] interfaces = obj.getClass().getInterfaces();
        //3.产生代理对象(通过被代理对象的类加载器及实现的接口)
        //第一个参数:被代理对象的类加载器
        //第二个参数:被代理对象实现的接口
        //第三个参数:使用产生代理对象调用方法时,用于拦截方法执行的处理器
        Object proxy = Proxy.newProxyInstance(classLoader, interfaces,this);
        return proxy;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        begin();
        Object returnValue = method.invoke(obj,args);  //执行method方法(insert)
        commit();
        return returnValue;
    }

    public void begin(){
        System.out.println("----------开启事务");
    }

    public void commit(){
        System.out.println("----------提交事务");
    }
}

测试代码

 //创建被代理对象
BookDAOImpl bookDAO = new BookDAOImpl();
StudentDAOImpl studentDAO = new StudentDAOImpl();

//创建动态代理类对象,并将被代理对象传递到代理类中赋值给obj
JDKDynamicProxy jdkDynamicProxy = new JDKDynamicProxy(studentDAO);

//proxy就是产生的代理对象:产生的代理对象可以强转成被代理对象实现的接口类型
GenaralDAO proxy = (GenaralDAO)jdkDynamicProxy.getProxy();

//使用代理对象调用方法,并不会执行调用的方法,而是进入到创建代理对象时指定的InvocationHandler类种的invoke方法
//调用的方法作为一个Method参数,传递给了invoke方法
proxy.insert(student);

28.2  CGLib动态代理

JDK是通过被代理类实现InvocationHandler接口来产生代理对象的,如果一个类没有实现接口,改如何产生代理对象呢?

CGLib动态代理,是通过创建被代理类的子类来创建代理对象的,因此即使没有实现任何接口,也可以通过CGLib动态代理产生代理对象。----因此CGLib动态代理不能够产生 final类 的代理对象

  1. 添加CGLib依赖
  2. 创建CGLib代理类,实现MethodInterceptor接口,重写intercept方法
  3. 类中定义一个Object类型的变量,并提供这个变量的有参构造器,用于传递被代理对象
  4. 定义getProxy方法创建并返回代理对象(代理对象是通过创建被代理类的子类来创建的)
public class CGLibDynamicProxy implements MethodInterceptor {

    private Object obj;
    public CGLibDynamicProxy(Object obj) {
        this.obj = obj;
    }

    public Object getProxy(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(obj.getClass());
        enhancer.setCallback(this);
        Object proxy = enhancer.create();
        return proxy;
    }


    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        begin();
        Object returnValue = method.invoke(obj,objects); //通过反射调用被代理类的方法
        commit();
        return returnValue;
    }

    public void begin(){
        System.out.println("----------开启事务");
    }

    public void commit(){
        System.out.println("----------提交事务");
    }
}

测试

//创建被代理对象
BookDAOImpl bookDAO = new BookDAOImpl();
StudentDAOImpl studentDAO = new StudentDAOImpl();

//通过cglib动态代理类创建代理对象
CGLibDynamicProxy cgLibDynamicProxy = new CGLibDynamicProxy(bookDAO);
//代理对象实际上是被代理对象子类,因此代理对象可直接强转为被代理类类型
BookDAOImpl proxy = (BookDAOImpl) cgLibDynamicProxy.getProxy();

//使用对象调用方法,实际上并没有执行这个方法,而是执行了代理类中的intercept方法,将当前调用的方法以及方法中的参数传递到intercept方法
proxy.update();

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

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

相关文章

@ConfigurationProperties在方法上的使用

文章目录1. 前言2. 先说结论3. 代码解释1. Component ConfigurationProperties2. EnableConfigurationProperties ConfigurationProperties3. Bean ConfigurationProperties1. 前言 在学习spring的时候&#xff0c;ConfigurationProperties应该经常被使用到&#xff0c;作用…

一文弄清混合云架构模式

当我们在说云架构的时候&#xff0c;通常指的并不是云平台的自身架构&#xff0c;而是基于云平台的软件系统基础架构。云平台的自身架构满足了很多通用层面的需求&#xff0c;例如对象存储&#xff0c;弹性主机&#xff0c;虚拟网络等等&#xff0c;只有云服务厂商的工程师才会…

Win10系统内置杀毒软件Windows Defender卸载方法

Windows10系统自带的Windows Defender杀毒软件&#xff0c;偶尔会使你的电脑CPU满负荷运载。 其实我们完全可以删除这个Windows10自带的杀毒软件&#xff0c;我们忍耐总是有限度的&#xff0c;所以&#xff0c;你可以选择删除它&#xff1b; 怎么删除呢&#xff1f;下面有个方…

Pthon--自动化实用技巧篇--文件目录处理

为什么要讲这一篇&#xff0c;主要是因为这个在自动化测试框架或者脚本的编写的时候会用到&#xff0c;还是比较方便的。看上述两个函数。getcwd()、chdir()。使用 os.getcwd() 函数获得当前工作目录。使用 os.chdir()函数改变当前工作目录。所以在用chdir()函数的时候别忘记指…

数据类型和变量

目录 ​编辑 一、字面常量 1、字面常量的定义 2、字面常量的分类 二、数据类型 三、变量 1、变量的概念 2、语法格式 3、整型变量 &#xff08;1&#xff09;整型变量 &#xff08;2&#xff09;长整型变量 &#xff08;3&#xff09;短整型变量 &#xff08;4&a…

带你深入了解c语言指针后续

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:介绍c语言中有关指针更深层的知识. 金句分享: ✨在该…

shell学习3

目录 一、查找并删除重复文件 二、列举文件类型统计信息 三、只列出目录 一、查找并删除重复文件 重复文件是同一个文件的多个副本。有时候我们需要删除重复的文件&#xff0c;只保留其中一份。通过查看文件内容来识别重复文件是件挺有意思的活儿。可以结合多种shell工具来完…

阶段六:服务框架基础(第二章Day-MQ(服务异步通讯))

阶段六&#xff1a;服务框架基础&#xff08;第二章Day-MQ&#xff08;服务异步通讯&#xff09;&#xff09;Day-RabbitMQ1.初识MQ1.1.同步和异步通讯1.1.1.同步通讯1.1.2.异步通讯1.2.技术对比&#xff1a;2.快速入门2.1.安装RabbitMQ 【重要】2.1.1、安装RabbitMQ&#xff0…

换掉 Maven,我就用Gradle,急速编译

相信使用Java的同学都用过Maven&#xff0c;这是一个非常经典好用的项目构建工具。但是如果你经常使用Maven&#xff0c;可能会发现Maven有一些地方用的让人不太舒服&#xff1a; Maven的配置文件是XML格式的&#xff0c;假如你的项目依赖的包比较多&#xff0c;那么XML文件就…

[Datawhale][CS224W]图机器学习(六)

目录一、简介二、概述三、算法四、PageRank的缺点五、Python实现迭代法参考文献一、简介 PageRank&#xff0c;又称网页排名、谷歌左侧排名、PR&#xff0c;是Google公司所使用的对其搜索引擎搜索结果中的网页进行排名的一种算法。 佩奇排名本质上是一种以网页之间的超链接个…

蒙特卡洛随机模拟

蒙特卡洛随机模拟 简介 蒙特卡洛模拟是在计算机上模拟项目实施了成千上万次&#xff0c;每次输入都随机选择输入值。由于每个输入很多时候本身就是一个估计区间&#xff0c;因此计算机模型会随机选取每个输入的该区间内的任意值&#xff0c;通过大量成千上万甚至百万次的模拟…

笔记本触摸板没反应怎么办?处理方法看这些

触摸板在笔记本电脑中是非常重要的一部分&#xff0c;很多用户都会选择使用触摸板代替鼠标。然而&#xff0c;有时你可能会发现&#xff0c;你的笔记本电脑触摸板没反应&#xff0c;无法正常使用。这对于日常使用来说是非常困扰的&#xff0c;但不用担心&#xff0c;我们将在这…

JavaScript BOM【快速掌握知识点】

目录 Window对象的常用属性 语法&#xff1a; Window对象的常用方法 语法&#xff1a; open()和close()方法 History对象 常用属性和方法 示例 Location对象 常用属性 常用方法 Document对象的常用方法 定时函数 超时调用&#xff1a;setTimeout() 间歇调用&…

插件化框架shadow——腾讯

theme: cyanosis Shadow简介 Shadow是最近腾讯开源的一款插件化框架。原理是使用宿主代理的方式实现组件的生命周期。目前的插件化框架&#xff0c;大部分都是使用hook系统的方式来做的。使用代理的基本上没有成体系的框架&#xff0c;只是一些小demo&#xff0c;Shadow框架的…

【华为OD机试模拟题】用 C++ 实现 - 查找单入口空闲区域(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明查找单入口空闲区域题目输入输出示例一输入输出说明示例二输入输出说明示例三输入输出说明示例

在linux中web服务器的搭建与配置

以下涉及到的linux命令大全查阅 https://www.runoob.com/linux/linux-command-manual.htmlvim命令查阅 https://www.runoob.com/linux/linux-vim.htmlscp命令https://www.runoob.com/linux/linux-comm-scp.html首先要有一个请求的服务地址用ssh 进入到linux系统中ssh 请求的服务…

JavaWeb Servlet Cookie和Session

6、Servlet 6.1、Servlet简介 Servlet就是sun公司开发动态web的一门技术Sun在这些API中提供一个接口叫做&#xff1a;Servlet&#xff0c;如果你想开发一个Servlet程序&#xff0c;只需要完成两个小步骤&#xff1a; 编写一个类&#xff0c;实现Servlet接口把开发好的Java类部…

Redis 4种集群方案介绍+优缺点对比

前言在服务开发中&#xff0c;单机都会存在单点故障的问题&#xff0c;即服务部署在一台服务器上&#xff0c;一旦服务器宕机服务就不可用&#xff0c;所以为了让服务高可用&#xff0c;分布式服务就出现了&#xff0c;将同一服务部署到多台机器上&#xff0c;即使其中几台服务…

【LeetCode】剑指 Offer 17. 打印从1到最大的n位数 p114 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/ 1. 题目介绍&#xff08;17. 打印从1到最大的n位数&#xff09; 输入数字 n&#xff0c;按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3&#xff0c;则打印出 1、2、3 一直…

<JVM上篇:内存与垃圾回收篇>12 - 垃圾回收相关概念

笔记来源&#xff1a;尚硅谷 JVM 全套教程&#xff0c;百万播放&#xff0c;全网巅峰&#xff08;宋红康详解 java 虚拟机&#xff09; 文章目录12.1. System.gc()的理解12.2. 内存溢出与内存泄露内存溢出&#xff08;OOM&#xff09;内存泄漏&#xff08;Memory Leak&#xff…