深入理解Spring两大特性:IoC和AOP

深入理解Spring两大特性:IoC和AOPJavaEE 目录 https blog csdn net dkbnull article details nbsp 众所周知 Spring 拥有两大特性 IoC 和 AOP IoC 英文全称 InversionofC 意为控制反转 AOP 英文全称 Aspect OrientedProg 意为面向切面编程 Spring 核心容器的主要组件是 Bean 工

Java EE 目录:https://blog.csdn.net/dkbnull/article/details/

 

众所周知,Spring拥有两大特性:IoC和AOP。IoC,英文全称Inversion of Control,意为控制反转。AOP,英文全称Aspect-Oriented Programming,意为面向切面编程

Spring核心容器的主要组件是Bean工厂(BeanFactory),Bean工厂使用控制反转(IoC)模式来降低程序代码之间的耦合度,并提供了面向切面编程(AOP)的实现。

简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面编程(AOP)的容器框架

下面,我们简要说明下这两大特性。

 

1. Spring常用注解

在具体介绍IoC和AOP之前,我们先简要说明下Spring常用注解

1、@Controller:用于标注控制器层组件

2、@Service:用于标注业务层组件

3、@Component : 用于标注这是一个受 Spring 管理的组件,组件引用名称是类名,第一个字母小写。可以使用@Component(“beanID”) 指定组件的名称

4、@Repository:用于标注数据访问组件,即DAO组件

5、@Bean:方法级别的注解,主要用在@Configuration和@Component注解的类里,@Bean注解的方法会产生一个Bean对象,该对象由Spring管理并放到IoC容器中。引用名称是方法名,也可以用@Bean(name = “beanID”)指定组件名

6、@Scope(“prototype”):将组件的范围设置为原型的(即多例)。保证每一个请求有一个单独的action来处理,避免action的线程问题。

由于Spring默认是单例的,只会创建一个action对象,每次访问都是同一个对象,容易产生并发问题,数据不安全。

7、@Autowired:默认按类型进行自动装配。在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。

8、@Resource:默认按名称进行自动装配,当找不到与名称匹配的Bean时会按类型装配。

 

简单点说,就是,能够明确该类是一个控制器类组件的,就用@Controller;能够明确是一个服务类组件的,就用@Service;能够明确该类是一个数据访问组件的,就用@Repository;不知道他是啥或者不好区分他是啥,但是就是想让他动态装配的就用@Component。

@Controller、@Service、@Component、@Repository都是类级别的注解,如果一个方法也想动态装配,就用@Bean

当我们想按类型进行自动装配时,就用@Autowired;当我们想按名称(beanID)进行自动装配时,就用@Resource;当我们需要根据比如配置信息等来动态装配不同的组件时,可以用getBean(“beanID”)。

到这里,如果对这些注解,或是自动装配不太理解,可以继续往下,看完 控制反转(IoC) 内容后再回来理解这里的内容。

 

2. 控制反转(IoC)

控制反转,简单点说,就是创建对象的控制权,被反转到了Spring框架上。

通常,我们实例化一个对象时,都是使用类的构造方法来new一个对象,这个过程是由我们自己来控制的,而控制反转就把new对象的工交给了Spring容器。

expert ONE-ON-ONE J2EE Development without EJB》第6章中指出

P128

IoC Implementation Strategies

IoC is a broad concept that can be implemented in different ways. There are two main types:

Dependency Lookup: The container provides callbacks to components, and a lookup context.This is the EJB and Apache Avalon approach. It leaves the onus on each component to use container APIs to look up resources and collaborators. The Inversion of Control is limited to the container invoking callback methods that application code can use to obtain resources.

Dependency Injection: Components do no look up; they provide plain Java methods enabling the container to resolve dependencies. The container is wholly responsible for wiring up components, passing resolved objects in to JavaBean properties or constructors. Use of JavaBean properties is called Setter Injection; use of constructor arguments is called Constructor Injection.

P130

The second IoC strategy-Dependency Injection-is usually preferable.

主要意思为:

IoC的主要实现方式有两种:依赖查找、依赖注入。

依赖注入是一种更可取的方式。

那么依赖查找和依赖注入有什么区别呢?

依赖查找,主要是容器为组件提供一个回调接口和上下文环境。这样一来,组件就必须自己使用容器提供的API来查找资源和协作对象,控制反转仅体现在那些回调方法上,容器调用这些回调方法,从而应用代码获取到资源。

依赖注入,组件不做定位查询,只提供标准的Java方法让容器去决定依赖关系。容器全权负责组件的装配,把符合依赖关系的对象通过Java Bean属性或构造方法传递给需要的对象。

2.1 IoC容器

IoC容器:具有依赖注入功能的容器,可以创建对象的容器。IoC容器负责实例化、定位、配置应用程序中的对象并建立这些对象之间的依赖。

2.2 依赖注入

DI,英文全称,Dependency Injection,意为依赖注入。

依赖注入:由IoC容器动态地将某个对象所需要的外部资源(包括对象、资源、常量数据)注入到组件(Controller, Service等)之中。简单点说,就是IoC容器会把当前对象所需要的外部资源动态的注入给我们

Spring依赖注入的方式主要有四个,基于注解注入方式、set注入方式、构造器注入方式、静态工厂注入方式。推荐使用基于注解注入方式,配置较少,比较方便。

基于注解注入方式

服务层代码

@Service public class AdminService { //code } 

控制层代码

@Controller @Scope("prototype") public class AdminController { @Autowired private AdminService adminService; //code } 

@Autowired与@Resource都可以用来装配Bean,都可以写在字段、setter方法上。他们的区别是:

@Autowired默认按类型进行自动装配(该注解属于Spring),默认情况下要求依赖对象必须存在,如果要允许为null,需设置required属性为false,例:@Autowired(required=false)。如果要使用名称进行装配,可以与@Qualifier注解一起使用。

 @Autowired @Qualifier("adminService") private AdminService adminService; 

@Resource默认按照名称进行装配(该注解属于J2EE),名称可以通过name属性来指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行装配;如果注解写在setter方法上,默认取属性名进行装配。当找不到与名称相匹配的Bean时,会按照类型进行装配。但是,name属性一旦指定,就只会按照名称进行装配。

 @Resource(name = "adminService") private AdminService adminService; 

 

除此之外,对于一些复杂的装载Bean的时机,比如我们需要根据配置装载不同的Bean,以完成不同的操作,可以使用getBean(“beanID”)的方式来加载Bean。

通过BeanID加载Bean方法如下:

@Component public class BeanUtils implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) { if (BeanUtils.applicationContext == null) { BeanUtils.applicationContext = applicationContext; } } public static ApplicationContext getApplicationContext() { return applicationContext; } public static Object getBean(String id) throws Exception { try { return applicationContext.containsBean(id) ? applicationContext.getBean(id) : null; } catch (BeansException e) { e.printStackTrace(); throw new Exception("not found bean id: " + id); } } } 

我们在需要装载Bean的地方调用该方法即可

public class BaseController { protected IService loadService(String id) throws Exception { IService iService = (IService) BeanUtils.getBean(id); if (iService != null) { return iService; } else { throw new Exception("加载Bean错误"); } } } 

3. 面向切面编程(AOP)

面向切面编程(AOP)就是纵向的编程。比如业务A和业务B现在需要一个相同的操作,传统方法我们可能需要在A、B中都加入相关操作代码,而应用AOP就可以只写一遍代码,A、B共用这段代码。并且,当A、B需要增加新的操作时,可以在不改动原代码的情况下,灵活添加新的业务逻辑实现。

在实际开发中,比如商品查询、促销查询等业务,都需要记录日志、异常处理等操作,AOP把所有共用代码都剥离出来,单独放置到某个类中进行集中管理,在具体运行时,由容器进行动态织入这些公共代码。

AOP主要一般应用于签名验签、参数校验、日志记录、事务控制、权限控制、性能统计、异常处理等。

3.1 AOP涉及名词

切面(Aspect):共有功能的实现。如日志切面、权限切面、验签切面等。在实际开发中通常是一个存放共有功能实现的标准Java类。当Java类使用了@Aspect注解修饰时,就能被AOP容器识别为切面。

通知(Advice):切面的具体实现。就是要给目标对象织入的事情。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。在实际开发中通常是切面类中的一个方法,具体属于哪类通知,通过方法上的注解区分。

连接点(JoinPoint):程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出等。Spring只支持方法级的连接点。一个类的所有方法前、后、抛出异常时等都是连接点。

切入点(Pointcut):用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。

比如,在上面所说的连接点的基础上,来定义切入点。我们有一个类,类里有10个方法,那就产生了几十个连接点。但是我们并不想在所有方法上都织入通知,我们只想让其中的几个方法,在调用之前检验下入参是否合法,那么就用切点来定义这几个方法,让切点来筛选连接点,选中我们想要的方法。切入点就是来定义哪些类里面的哪些方法会得到通知。

目标对象(Target)那些即将切入切面的对象,也就是那些被通知的对象。这些对象专注业务本身的逻辑,所有的共有功能等待AOP容器的切入。

代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象本身业务逻辑加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。目标对象被织入共有功能后产生的对象。

织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译时、类加载时、运行时。Spring是在运行时完成织入,运行时织入通过Java语言的反射机制与动态代理机制来动态实现。

3.2 Pointcut用法

Pointcut格式为:

execution(modifier-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

修饰符匹配 modifier-pattern? 例:public private

返回值匹配 ret-type-pattern 可以用 * 表示任意返回值

类路径匹配 declaring-type-pattern? 全路径的类名

方法名匹配 name-pattern 可以指定方法名或者用 * 表示所有方法;set* 表示所有以set开头的方法

参数匹配 (param-pattern) 可以指定具体的参数类型,多个参数用“,”分隔;可以用 * 表示匹配任意类型的参数;可以用 (..) 表示零个或多个任意参数

异常类型匹配throws-pattern? 例:throws Exception

其中后面跟着 ? 表示可选项

例:

@Pointcut("execution(public * cn.wbnull. springbootdemo.controller.*.*(..))") private void sign() { } 

 

3.3 一个例子

以 Spring Boot入门:使用AOP实现拦截器 中的AOP为例

@Aspect @Component public class SignAop { } 

SignAop类使用了@Aspect注解,则该类可以被AOP容器识别为切面。

 

@Aspect @Component public class SignAop { @Pointcut("execution(public * cn.wbnull.springbootdemo.controller.*.*(..))") private void signAop() { } } 

@Pointcut声明一个切入点,范围为controller包下所有的类的所有方法

注:作为切入点签名的方法必须返回void类型

 

@Aspect @Component public class SignAop { @Pointcut("execution(public * cn.wbnull.springbootdemo.controller.*.*(..))") private void signAop() { } @Before("signAop()") public void doBefore(JoinPoint joinPoint) throws Exception { //code } @AfterReturning(value = "signAop()", returning = "params") public JSONObject doAfterReturning(JoinPoint joinPoint, JSONObject params) { //code } } 

doBefore()方法使用@Before(“signAop()”)注解,表示前置通知(在某连接点之前执行的通知),但这个通知不能阻止连接点之前的执行流程,除非它抛出一个异常。

doAfterReturning()方法使用@AfterReturning(value = “signAop()”, returning = “params”)注解,表示后置通知(在某连接点正常完成后执行的通知),通常在一个匹配的方法返回的时候执行。

实际运行时,在进入controller包下所有方法前,都会进入doBefore()方法,在controller包下方法执行完成后,都会进入doAfterReturning()方法。

 

AOP具体使用可以参考 Spring Boot入门:使用AOP实现拦截器

 

到这里,Spring两大特性IoC和AOP基本讲述完成,后续若想起其他再进行补充。

 

微信:https://mp.weixin..com/s/Si7kodmH-GnMh-D2nk_DVQ

 

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/202649.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午11:38
下一篇 2026年3月19日 下午11:38


相关推荐

  • 二叉排序树(二叉查找树、二叉搜索树)

    二叉排序树(二叉查找树、二叉搜索树)什么是二叉查找树 根节点的值大于其左子树中任意一个节点的值 小于其右节点中任意一节点的值 这一规则适用于二叉查找树中的每一个节点 本文章重点来讨论一下关于二叉查找树删除节点的问题 有一下二叉查找树 如图 在删除节点的时候我们只需考虑一下三种情况 1 要删除的节点是叶子结点 如图 2 要删除的节点有左节点但是没有右节点 或者有右节点但是没有左节点 如图 3 要删除的节点既有

    2026年3月20日
    2
  • linux ubuntu 关闭防火墙命令,Linux下开启/关闭防火墙命令「建议收藏」

    iptables用于过滤数据包,属于网络层防火墙.firewall能够允许哪些服务可用,那些端口可用….属于更高一层的防火墙。firewall的底层是使用iptables进行数据过滤,建立在iptables之上。1)永久性生效,重启后不会复原开启:chkconfigiptableson关闭:chkconfigiptablesoff2)即时生效,重启后复原开启:service…

    2022年4月9日
    213
  • intellj 激活码2021(最新序列号破解)

    intellj 激活码2021(最新序列号破解),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月18日
    110
  • 数据库入门基础[通俗易懂]

    数据库入门基础[通俗易懂]一、什么是数据库很多人不明白,存储数据用文件就可以了,为什么还要弄个数据库?首先文件保存数据有以下几个缺点:·文件的安全性问题·文件不利于数据查询和管理·文件不利于存储海量数据·文件在程序中控制不方便为了解决上述问题,专家们设计出更加利于管理数据的软件——数据库,它能更有效的管理数据。数据库可以提供远程服务,即通过远程连接来使用数据库,因此也称为数据库服务器。数据库存储介质…

    2022年6月20日
    36
  • java fel_开发中常用Fel的写法

    java fel_开发中常用Fel的写法直接看代码吧 packagejavad importjava util HashMap importjava util Map importcom greenpineyu fel Expression importcom greenpineyu fel FelEngine importcom greenpineyu fel FelEngineImp importcom gre

    2026年3月16日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号