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的语法和功能。
相关推荐
- 全局和隐式 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不足之处加以改进,核心改进...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- .NET 奇葩问题调试经历之3——使用了grpc通讯类库后,内存一直增长......
- 全局和隐式 using 指令详解(全局命令)
- 请停止微服务,做好单体的模块化才是王道:Spring Modulith介绍
- ASP.NET程序集引用之痛:版本冲突、依赖地狱等解析与实战
- .NET AOT 详解(.net 6 aot)
- 一款基于Yii2开发的免费商城系统(一款基于yii2开发的免费商城系统是什么)
- asar归档解包(游戏arc文件解包)
- 在PyCharm 中免费集成Amazon CodeWhisperer
- 2014年最优秀JavaScript编辑器大盘点
- 基于springboot、tio、oauth2.0前端vuede 超轻量级聊天软件分享
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)