百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

Spring框架基础知识-第二节内容(spring框架介绍及使用)

yuyutoo 2025-07-06 17:45 5 浏览 0 评论

Spring容器的接口

基本概念

Spring的容器有两个接口:BeanFactory和ApplicationContext,这两个接口的实例被称为Spring上下文,它们都是用来产生Bean的工厂,即负责创建和管理Bean。在实际的应用中,我们推荐使用ApplicationContext接口,它是BeanFactory的子接口,具有比BeanFactory接口更完善的功能。

ConfigurableApplicationContext

基本概念


ConfigurableApplicationContext是Spring框架中的SPI(Service Provider Interface)接口,继承自ApplicationContext、Lifecycle和Closeable接口。它是为Spring容器的配置和生命周期管理而设计的核心接口。

源码



接口层次结构



主要方法

setId(String id)

设置应用上下文的唯一标识

setParent(ApplicationContext parent)

设置父容器

setEnvironment(ConfigurableEnvironment environment)

设置环境配置

getEnvironment()

获取可配置的环境对象

refresh()

最重要方法,刷新容器配置,加载Bean定义

start()

启动容器

stop()

停止容器

close()

关闭容器,释放所有资源

isActive()

判断容器是否处于活跃状态

使用场景

1、容器生命周期管理



2、添加后置处理器



与ApplicationContext的区别

ApplicationContext - 面向客户端的只读接口


ConfigurableApplicationContext - 面向框架内部的可配置接口,提供容器的配置和生命周期管理能力

总结


ConfigurableApplicationContext是Spring容器管理的核心接口,掌握它对理解Spring容器的工作机制至关重要。

ApplicationContext接口的实现类

(1)ClassPathXmlApplicationContext

主要用来从类路径(CLASSPATH)中的xml文件载入上下文定义信息。

(2)FileSystemXmlApplicationContext

从指定的文件系统路径中的xml文件载入上下文定义信息。

(3)XmlWebApplicationContext

从Web系统中的xml文件中载入上下文定义信息。

(4)AnnotationConfigApplicationContext

当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

创建Spring上下文实例

在创建Spring上下文的实例时,必须提供Spring容器管理的Bean的详细配置信息。因此在创建Spring上下文实例时,应该提供xml配置文件作为参数传入。代码如下:

BeanFactory factory =

         new
ClassPathXmlApplicationContext

               ("classpath:application.xml");

可以在参数字符串中使用通配符*来加载多个具有相同部分名称的配置文件,代码如下:

BeanFactory factory =

         new
ClassPathXmlApplicationContext

              ("classpath:application*.xml");

在创建完Spring上下文实例后,要从上下文中获取Bean的实例,只需要使用它的getBean(String name)方法获取

Spring配置文件(xml文件)

Spring容器要管理的Bean是通过xml文件来配置的。在Spring的配置文件中,可以使用import标签导入项目中的其他spring配置文件,便于管理和使用。

1、装配Bean

在Spring配置文件中,使用bean元素来装配一个Bean,它常用的属性包括以下九种:

   id:设置该Bean的唯一标识。

   class:指定该Bean的全限定名。

   name:为该Bean指定一个或多个别名,多个别名用空格、“,”或“;”分隔。

   autowire:指定该Bean属性的装配方式。

   scope:指定该Bean的存在范围。

   int-method:指定该Bean的初始化方法

   destroy-method:指定该Bean的销毁方法

   abstract:指定该Bean是否为抽象的,如果是,则Spring不为它创建实例

   parent:指定该Bean的父类标识或别名。

2、简单类型属性值的装配

通过bean元素的子元素property来设置。这样配置之后,Spring容器在创建和初始化这个Bean时,Spring容器将根据配置文件中的设置对所有需要装配值的属性调用setter()方法,所以需要在Bean类的程序代码中为属性添加setter()方法。

示例:

<property name="name" value="靳世辉" />

<property name="age" value="22"/>

3、引用其他Bean的装配

如果Bean的某个属性是复杂类型的,即它引用自其他的Bean,那么在Spring配置文件中可以使用property元素的ref属性来引用

<property name="address" ref="addressbean"></property>

4、集合属性的装配

如果需要注入的不只是一个对象,而是一个对象集,这就需要通过集合或数组属性的装配来实现。Spring支持多种类型的集合作为属性,如:数组、List、Set、Map、Properties。List属性用list元素装配,Set属性用set元素装配,Map属性用map元素装配。Properties属性用props装配。在java.util 包下面有一个类 Properties,该类主要用于读取项目的配置文件(以.properties结尾的文件和xml文件)。

5、空值的装配

如果要把某个对象属性的值明确设置为null,可以在Spring配置文件中使用null元素来指定

示例:

<property name="name">

<null></null>

</property>

6、自动装配

Spring能自动装配Bean的属性,仅设置要自动装配的bean中的autowire属性即可。在实际项目开发中,一般不建议使用自动装配,这是因为由于依赖关系的装配依赖于源文件的属性名,这样Bean和Bean之间的耦合关系转移到了代码层面,这样会给编码带来麻烦。

no:不使用自动装配。Bean的属性必须通过显式装配定义,这是默认值,一般都不建议使用自动装配。

byName:根据属性名进行自动装配

byType:根据属性类型自动装配

Constructor:跟byType类似,采用构造器注入

autodetect:根据Bean的内部结构,首先尝试使用constructor来自动装配,然后再使用byType方式。

7、指定Bean的初始化和销毁方法

Spring可以管理Bean实例在实例化结束后和被销毁之前的行为。通过bean元素的init-method属性可以指定某个方法应该在Bean全部依赖设置结束后自动执行;通过bean元素的destroy-method属性可以指定某个方法应该在Bean被销毁之前自动执行。需要注意的是,被指定用来初始化或销毁的方法不能有参数。

8、指定Bean的存在范围

在装配Bean时,还可以通过bean元素的scope属性来指定Bean的生存范围,取值如下:

singleton:Spring IOC容器只会创建该bean定义的唯一实例,这是系统的默认值。

prototype:每次对Bean请求时都会创建一个新的Bean实例,一个Bean定义多个实例。

request:在HTTP请求范围内,只有在使用具有Web能力的Spring容器时才有效

session:在HTTP Session范围内,只有在使用具有Web能力的Spring容器时才有效。

global_session:全局HTTP Session,只有在portlet上下文中有效。

9、装配Bean的继承

  如果两个Bean的属性装配信息很相似,那么可以利用继承来减少重复的配置工作。Spring中的继承是指子Bean可以从父Bean中继承配置信息,也可以覆盖指定的配置信息,或添加自己的配置,这样可以节省很多配置工作。

注意:父类中必须指定abstract="true",不能让父类实例化,子类指定parent="parent",引用父类的id名称。

<!-- 装配Bean的继承

父类作为模板,不需要实例化,设置abstract="true"-->

<bean id="parent" class="dao.Parent" abstract="true">

<property name="name" value="ACCP"></property>

<property name="pwd" value="123456"></property>

</bean>

<!-- 装配Bean的继承

子类中用parent属性指定父类标识或别名

子类可以覆盖父类的属性装配,也可以新增自己的属性装配 -->

<bean id="child" class="dao.Child" parent="parent">

<property name="pwd" value="ACCP123"></property>

<property name="address" value="北京海淀区"></property>

</bean>

10、IOC容器

(1)实例化具体的bean。

(2)动态装配

id与name的区别:name中可以添加特殊字符,而id中不可以。如果某个类是struts action,那么scope设置为prototype。第一次初始化Spring配置文件时,会创建所有的对象。init和destroy方法不要和prototype一起使用。

Spring配置文件详细说明


如何在Spring中启动注解装配

默认情况下Spring 容器中未打开注解装配。 因此要使用基于注解装配,我们必须通过配置 <context: annotation-config />元素在Spring的配置文件中启用它。

Spring使用注解进行配置

Spring2.5引入了注解功能。

注释配置相对于XML 配置具有很多的优势

(1)它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作。

(2)注释和 Java 代码位于一个文件中,而 XML 配置采用独立的配置文件,大多数配置信息在程序开发完成后都不会调整,如果配置信息和 Java 代码放在一起,有助于增强程序的内聚性。而采用独立的 XML 配置文件,程序员在编写一个功能时,往往需要在程序文件和配置文件中不停切换,这种思维上的不连贯会降低开发效率

(1)修改xml文件,添加注解配置

需要添加: xmlns:context="
http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context/spring-context-2.5.xsd

说明:添加spring-context-2.5.xsd这个标记

(2)@Autowired

对成员变量、方法和构造函数进行标注来完成自动注入,默认按类型注入。Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。当找不到一个匹配的 Bean 时,Spring 容器将抛出BeanCreationException 异常,并指出必须至少拥有一个匹配的 Bean。

(3)@Qualifier

可以对成员变量、方法以及构造函数进行注释,而 @Qualifier 的标注对象是成员变量、方法入参、构造函数入参。如果写在set方法上,@Qualifier需要写在方法的参数上。@Qualifier("XXX") 中的 XX是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变byName了。@Qualifier 只能和 @Autowired 结合使用,是对 @Autowired 有益的补充。一般来讲,@Qualifier 对方法签名中入参进行注释会降低代码的可读性,而对成员变量注释则相对好一些

示例:

@Autowired

@Qualifier("loginServiceImpl")

private LoginService loginService;

(4)@Resource

@Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,而@Resource 默认按 byName 自动注入罢了

不足:如果没有源码,就无法使用注解,只能使用xml文件。 要让resource注解生效,除了在 Bean 类中标注这些注释外,还需要在 Spring 容器中注册一个负责处理这些注释的 BeanPostProcessor:



<bean

class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>




CommonAnnotationBeanPostProcessor 实现了 BeanPostProcessor 接口,它负责扫描使用了 JSR-250 注释的 Bean,并对它们进行相应的操作。

@Autowired和@Resource的区别

1、包含的属性不同

2、@Autowired默认按byType自动装配,而@Resource默认byName自动装配。

@Autowired如果要使用byName,需要使用@Qualifier一起配合。而@Resource如果指定了name,则用byName自动装配,如果指定了type,则用byType自动装配。

3、注解应用的地方不同

@Autowired能够用在:构造器、方法、参数、成员变量和注解上,而@Resource能用在:类、成员变量和方法上

4、出处不同

@Autowired是Spring定义的注解,而@Resource是JSR-250定义的注解。所以@Autowired只能在Spring框架下使用,而@Resource则可以与其他框架一起使用。

5、装配顺序不同

@Autowired的装配顺序如下:

@Autowired默认先按byType进行匹配,如果发现找到多个bean,则又按照byName方式进行匹配,如果还有多个,则报出异常。



@Resource的装配顺序如下:

如果同时指定了name和type,流程如下:



如果指定了name,流程如下:

只是指定了@Resource注解的name,则按name后的名字去bean元素里查找有与之相等的name属性的bean。



如果指定了type,流程如下:

只指定@Resource注解的type属性,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常。



如果既没有指定name,也没有指定type,流程如下:

既不指定name属性,也不指定type属性,则自动按byName方式进行查找。如果没有找到符合的bean,则回退为一个原始类型进行进行查找,如果找到就注入。



(5)@PostContruct

Spring容器中的Bean是有生命周期的,Spring 允许 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,您既可以通过实现
InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法,也可以通过 <bean> 元素的
init-method/destroy-method 属性指定初始化之后/销毁之前调用的操作方法。

JSR-250 为初始化之后/销毁之前方法的指定定义了两个注释类,分别是 @PostConstruct 和 @PreDestroy,这两个注释只能应用于方法上。标注了 @PostConstruct 注释的方法将在类实例化后调用,而标注了@PreDestroy 的方法将在类销毁之前调用。

示例:



测试:



结果:



(6)@PreDestroy

标注了 @PreDestroy 的方法将在类销毁之前调用

(7)使用 <context:annotation-config/> 简化配置

Spring 2.1 添加了一个新的 context 的 Schema 命名空间,该命名空间对注释驱动、属性文件引入、加载期织入等功能提供了便捷的配置。我们知道注释本身是不会做任何事情的,它仅提供元数据信息。要使元数据信息真正起作用,必须让负责处理这些元数据的处理器工作起来。Spring 为我们提供了一种方便的注册注解的方式,这就是<
context:annotation-config/>

示例:



<
context:annotation-config/> 将隐式地向 Spring 容器注册
AutowiredAnnotationBeanPostProcessor、
CommonAnnotationBeanPostProcessor、
PersistenceAnnotationBeanPostProcessor 以及
equiredAnnotationBeanPostProcessor 这 4 个
BeanPostProcessor

在配置文件中使用 context 命名空间之前,必须在<beans>元素中声明 context 命名空间。

另外在我们使用注解时一般都会配置扫描包路径选项

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

该配置项其实也包含了自动注入上述processor的功能,因此当使用<context:component-scan/>后,即可将<
context:annotation-config/>省去。

(8)@Component

Spring 2.5 在 @Repository 的基础上增加了功能类似的额外三个注解:@Component、@Service、@Controller,它们分别用于软件系统的不同层次。

1、@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。

2、@Service 通常作用在业务层,但是目前该功能与 @Component 相同。

3、@Controller 通常作用在控制层,但是目前该功能与 @Component 相同。

4、通过在类上使用 @Repository、@Component、@Service 和 @Consroller 注解,Spring 会自动创建相应的 Bean 对象,并注册到 ApplicationContext 中,这些类就成了 Spring 受管组件。这三个注解除了作用于不同软件层次的类,其使用方式与 @Repository 是完全相同的。

5、@Component 有一个可选的入参,用于指定 Bean的名称。一般情况下,Bean 都是 singleton 的,需要注入 Bean 的地方仅需要通过 byType 策略就可以自动注入了,所以大可不必指定 Bean 的名称。在使用 @Component 注释后,Spring 容器必须启用类扫描机制以启用注释驱动 Bean 定义和注释驱动 Bean 自动注入的策略。

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

这里所有通过 <bean> 元素定义 Bean 的配置内容已经被移除,仅需要添加一行 <context:component-scan/> 配置就解决所有问题了,Spring XML 配置文件得到了极致的简化(当然配置元数据还是需要的,只不过以注释形式存在罢了)。<context:component-scan/> 的 base-package 属性指定了需要扫描的类包,类包及其递归子包中所有的类都会被处理

<context:component-scan/> 还允许定义过滤器将基包下的某些类纳入或排除。Spring 支持以下 4 种类型的过滤方式,通过下表说明:



示例:

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

<context:include-filter type="regex"

expression="com\.baobaotao\.service\..*"/>

<context:exclude-filter type="aspectj"

expression="com.baobaotao.util..*"/>

</context:component-scan>

值得注意的是 <context:component-scan/> 配置项不但启用了对类包进行扫描以实施注释驱动 Bean 定义的功能,同时还启用了注释驱动自动注入的功能(即还隐式地在内部注册了
AutowiredAnnotationBeanPostProcessor 和
CommonAnnotationBeanPostProcessor),
因此当使用 <context:component-scan/> 后,就可以将 <
context:annotation-config/> 移除了
。默认情况下通过 @Component 定义的 Bean 都是 singleton 的,如果需要使用其它作用范围的 Bean,可以通过@Scope 注释来达到目标。

(9)@Scope

通过@scope指定Bean的作用范围

示例:



这样当从 Spring 容器中获取 boss Bean 时,每次返回的都是新的实例了。

(10)@Configuration

用@Configuration注解类,等价于XML中配置beans

(11)@Bean

@Bean这个注释用在方法上,用于创建一个Bean,并且交给Spring容器管理

示例:

新建Piano类:



新建Counter类:



新建SpringConfig类:



测试:



(12)采用具有特殊语义的注释

Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service 和@Controller。在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的,但是从注释类的命名上,很容易看出这 3 个注释分别和持久层、业务层和控制层(Web 层)相对应。虽然目前这 3 个注释和@Component 相比没有什么新意,但 Spring 将在以后的版本中为它们添加特殊的功能。所以如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用@Repository、@Service 和 @Controller 对分层中的类进行注释,而用@Component 对那些比较中立的类进行注释。

(13)注释配置和 XML 配置的适用场合

1、注释配置不一定在先天上优于 XML 配置。如果 Bean 的依赖关系是固定的,(如 Service 使用了哪几个 DAO 类),这种配置信息不会在部署时发生调整,那么注释配置优于 XML 配置;反之如果这种依赖关系会在部署时发生调整,XML 配置显然又优于注释配置,因为注释是对Java 源代码的调整,您需要重新改写源代码并重新编译才可以实施调整。

2、如果Bean不是自己编写的类(如 JdbcTemplate、SessionFactoryBean 等),注释配置将无法实施,此时 XML 配置是唯一可用的方式。

3、注释配置往往是类级别的,而 XML 配置则可以表现得更加灵活。比如相比于 @Transaction 事务注释,使用 aop/tx 命名空间的事务配置更加灵活和简单。

4、在实现应用中,我们往往需要同时使用注释配置和 XML 配置,对于类级别且不会发生变动的配置可以优先考虑注释配置;而对于那些第三方类以及容易发生调整的配置则应优先考虑使用 XML 配置。Spring会在具体实施Bean创建和 Bean 注入之前将这两种配置方式的元信息融合在一起。

AOP编程

概念

面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

适用的功能

主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等。

思想

面向切面编程的思想是:在执行某些代码前执行另外的代码,使程序更灵活、扩展性更好,可以随便的添加、删除某些功能

底层原理

动态AOP是指将切面代码进行动态织入实现的AOP。Spring的AOP为动态AOP,实现的技术为:JDK提供的动态代理和CGLIB代理(动态字节码增强技术)。Spring已经封装了动态代理

优点

1、通知自定义。

2、切面获得返回值。

3、解耦合。

4、统一管理权限,统一管理异常抛出。

基本知识点

1、切面(aspect)

一个关注点的模块化,这个关注点可能会横切多个对象,可以理解为模块。“切面”在Spring配置文件中用<aop:aspect>来配置

2、连接点(joinpoint)

程序执行过程中的某一行为

3、通知(advice)

通知定义了切面是什么以及何时使用,描述了切面要完成的工作和何时需要执行这个工作。一个“切面”可以包含多个通知, Advice共有如下5种类型:

前置通知(Before advice)

在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。xml中在<aop:aspect>里面使用<aop:before>元素进行声明

后通知(After advice)

当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。xml中在<aop:aspect>里面使用<aop:after>元素进行声明。

返回后通知(After return advice)

在某连接点正常完成后执行的通知,不包括抛出异常的情况。xml中在<aop:aspect>里面使用<after-returning>元素进行声明。注解中使用@AfterReturning声明

环绕通知(Around advice)

包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。xml中在<aop:aspect>里面使用<aop:around>元素进行声明。

抛出异常后通知(After throwing advice)

在方法抛出异常退出时执行的通知。xml中在<aop:aspect>里面使用<aop:after-throwing>元素进行声明。

4、切入点(pointcut)

业务逻辑代码添加的地点。匹配连接点的断言,在AOP中通知和一个切入点表达式关联。

(1)切入表达式

execution:用于匹配方法执行的连接点;

(2)匹配语法

* 匹配任何数量字符;

.. 匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。

+ 匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

5、目标对象(target object)

被一个或者多个切面所通知的对象。当然在实际运行时,Spring AOP采用代理实现,实际AOP操作的是TargetObject的代理对象

6、代理(proxy)

代理是将通知应用到目标对象后创建的对象。在Spring AOP中有两种代理方式:JDK动态代理和CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理,反之采用CGLIB代理,强制使用CGLIB代理需要将 <aop:config>的 proxy-target-class属性设为true。

7、织入(weaving)

把切面应用到目标对象来创建新的代理对象的过程,Spring是在运行时完成织入的。

具体的方法:通过配置文件去配置。(Spring2版本以上支持)

(1)添加被代理的对象(写实现类,实现类实现了相应的接口)

(2)添加额外的功能---切面(写引用类)

(3)代理工厂

<bean id="userdao" class="dao.UserDaoMySQLImpl"></bean>

<bean id="userservice" class="dao.UserServiceImpl">

<property name="userdao" ref="userdao"></property>

</bean>

<!-- 切面的类 -->

<bean id="logaspect" class="aspect.LogAspect"></bean>

<!-- AOP配置-->

<aop:config>

<!-- 配置一个切面 -->

<aop:aspect id="log" ref="logaspect">

<!-- 定义切入点,指定切入点表达式 -->

<aop:pointcut expression="execution(* dao.*.* (..))" id="allMethod"/>

<!-- 应用前置通知 -->

<aop:before method="before" pointcut-ref="allMethod"/>

<!-- 应用后置通知 -->

<aop:after-returning method="AfterReturn" pointcut-ref="allMethod"/>

<!-- 应用最终通知 -->

<aop:after method="after" pointcut-ref="allMethod"/>

<!-- 应用异常抛出 -->

<aop:after-throwing method="afterThrowing" pointcut-ref="allMethod"/>

</aop:aspect>

</aop:config>

说明:Spring中面向切面编程不需要编写动态代理

示例

1、定义切面类

public class TestAspect {

public void doAfter(JoinPoint jp) {

System.out.println("log Ending method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());

}


public Object doAround(ProceedingJoinPoint pjp) throws Throwable {

long time = System.currentTimeMillis();

Object retVal = pjp.proceed();

time = System.currentTimeMillis() - time;

System.out.println("process time: " + time + " ms");

return retVal;

}


public void doBefore(JoinPoint jp) {

System.out.println("log Begining method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());

}


public void doThrowing(JoinPoint jp, Throwable ex) {

System.out.println("method " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName() + " throw exception");

System.out.println(ex.getMessage());

}

}

2、定义目标对象

// 使用jdk动态代理

public class AServiceImpl implements AService {

public void barA() {

System.out.println("AServiceImpl.barA()");

}


public void fooA(String _msg) {

System.out.println("AServiceImpl.fooA(msg:" + _msg + ")");

}

}

// 使用cglib

public class BServiceImpl {


public void barB(String _msg, int _type) {

System.out.println("BServiceImpl.barB(msg:" + _msg + " type:" + _type + ")");

if (_type == 1)

throw new IllegalArgumentException("测试异常");

}


public void fooB() {

System.out.println("BServiceImpl.fooB()");

}


}

3、ApplicationContext:Spring配置文件

<?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:aop="http://www.springframework.org/schema/aop"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

<aop:config>

<aop:aspect id="TestAspect" ref="aspectBean">

<!--配置com.spring.service包下所有类或接口的所有方法-->

<aop:pointcut id="businessService" expression="execution(* com.spring.service.*.*(..))" />

<aop:before pointcut-ref="businessService" method="doBefore"/>

<aop:after pointcut-ref="businessService" method="doAfter"/>

<aop:around pointcut-ref="businessService" method="doAround"/>

<aop:after-throwing pointcut-ref="businessService" method="doThrowing" throwing="ex"/>

</aop:aspect>

</aop:config>


<bean id="aspectBean" class="com.spring.aop.TestAspect" />

<bean id="aService" class="com.spring.service.AServiceImpl"></bean>

<bean id="bService" class="com.spring.service.BServiceImpl"></bean>

</beans>

Spring AOP and AspectJ AOP的区别

实现机制差异

Spring AOP采用运行时代理机制:

1、基于JDK动态代理(接口代理)或CGLIB代理(类代理)

2、通过IoC容器在运行时创建代理对象

3、代理对象包装目标对象,在方法调用时插入切面逻辑

AspectJ AOP采用编译时织入机制:

1、通过专门的编译器ajc(AspectJ Compiler)进行字节码织入

2、支持编译时织入、类加载时织入和运行时织入三种方式

3、直接修改目标类的字节码,无需代理对象

功能特性对比

1、切点表达式支持

Spring AOP只支持方法级别的拦截,切点表达式相对简单。AspectJ支持更丰富的切点表达式,包括字段访问、构造器调用、异常处理等多种连接点。

2、织入时机

Spring AOP仅支持运行时织入,依赖Spring容器管理的bean。AspectJ支持编译时、类加载时和运行时三种织入方式,更加灵活。

3、性能表现

Spring AOP由于使用代理机制,会有一定的性能开销。AspectJ在编译时织入,运行时性能更好,因为没有代理层的开销。

语法和配置差异

Spring AOP配置示例



AspectJ原生语法



依赖和集成方式

Spring AOP完全集成在Spring框架中,无需额外的编译步骤,开发和部署相对简单。只需要在Spring配置中启用AOP支持即可。

AspectJ需要使用专门的编译器ajc,或者配置类加载时织入代理。在Maven或Gradle构建中需要特殊的插件支持,部署时可能需要额外的JVM参数。

适用场景选择

选择Spring AOP的情况:

1、项目已经使用Spring框架

2、主要需要方法级别的横切关注点

3、希望简化开发和部署流程

4、对性能要求不是特别高

选择AspectJ的情况:

1、需要字段级别或构造器级别的拦截

2、对性能有较高要求

3、需要在非Spring环境中使用AOP

4、需要更强大的切点表达式功能

学习曲线和维护成本

Spring AOP的学习曲线相对平缓,特别是对于已经熟悉Spring框架的开发者。AspectJ有自己的语法和概念,学习成本相对较高,但功能更加强大。

在实际项目中,许多开发者选择Spring AOP作为起点,当遇到Spring AOP无法满足的需求时,再考虑引入AspectJ的完整功能。Spring框架也提供了对AspectJ的良好集成支持,可以在Spring项目中使用AspectJ的语法和功能。

相关推荐

.NET 奇葩问题调试经历之3——使用了grpc通讯类库后,内存一直增长......

...

全局和隐式 using 指令详解(全局命令)

1.什么是全局和隐式using?在.NET6及更高版本中,Microsoft引入了...

请停止微服务,做好单体的模块化才是王道:Spring Modulith介绍

1、介绍模块化单体是一种架构风格,代码是根据模块的概念构成的。对于许多组织而言,模块化单体可能是一个很好的选择。它有助于保持一定程度的独立性,这有助于我们在需要的时候轻松过渡到微服务架构。Spri...

ASP.NET程序集引用之痛:版本冲突、依赖地狱等解析与实战

我是一位多年后端经验的工程师,其中前几年用ASP.NET...

.NET AOT 详解(.net 6 aot)

简介AOT(Ahead-Of-TimeCompilation)是一种将代码直接编译为机器码的技术,与传统的...

一款基于Yii2开发的免费商城系统(一款基于yii2开发的免费商城系统是什么)

哈喽,我是老鱼,一名致力于在技术道路上的终身学习者、实践者、分享者!...

asar归档解包(游戏arc文件解包)

要学习Electron逆向,首先要有一个Electron开发的程序的发布的包,这里就以其官方的electron-quick-start作为例子来进行一下逆向的过程。...

在PyCharm 中免费集成Amazon CodeWhisperer

CodeWhisperer是Amazon发布的一款免费的AI编程辅助小工具,可在你的集成开发环境(IDE)中生成实时单行或全函数代码建议,帮助你快速构建软件。简单来说,AmazonCodeWhi...

2014年最优秀JavaScript编辑器大盘点

1.WebstormWebStorm是一种轻量级的、功能强大的IDE,为Node.js复杂的客户端开发和服务器端开发提供完美的解决方案。WebStorm的智能代码编辑器支持JavaScript,...

基于springboot、tio、oauth2.0前端vuede 超轻量级聊天软件分享

项目简介:基于JS的超轻量级聊天软件。前端:vue、iview、electron实现的PC桌面版聊天程序,主要适用于私有云项目内部聊天,企业内部管理通讯等功能,主要通讯协议websocket。支持...

JetBrains Toolbox推出全新产品订阅授权模式

捷克知名软件开发公司JetBrains最为人所熟知的产品是Java编程语言开发撰写时所用的集成开发环境IntelliJIDEA,相信很多开发者都有所了解。而近期自2015年11月2日起,JetBr...

idea最新激活jetbrains-agent.jar包,亲测有效

这里分享一个2019.3.3版本的jetbrains-agent.jar,亲测有效,在网上找了很多都不能使用,终于找到一个可以使用的了,这里分享一下具体激活步骤,此方法适用于Jebrains家所有产品...

CountDownTimer的理解(countdowntomars)

CountDownTimer是android开发常用的计时类,按照注释中的说明使用方法如下:kotlin:object:CountDownTimer(30000,1000){...

反射为什么性能会很慢?(反射时为什么会越来越长)

1.背景前段时间维护一个5、6年前的项目,项目总是在某些功能使用上不尽人意,性能上总是差一些,仔细过了一下代码发现使用了不少封装好的工具类,工具类里面用了好多的反射,反射会影响到执行效率吗?盲猜了一...

btrace 开源!基于 Systrace 高性能 Trace 工具

介绍btrace(又名RheaTrace)是抖音基础技术团队自研的一款高性能AndroidTrace工具,它基于Systrace实现,并针对Systrace不足之处加以改进,核心改进...

取消回复欢迎 发表评论: