AOP和IOC详解

概述

        在Java中,AOP(面向切面编程)和IoC(控制反转)是两种常见的设计模式,它们在现代Java应用程序中,尤其是在Spring框架中扮演着重要的角色,在软件工程中广泛应用的设计原则,特别是在企业级应用程序开发中。它们都旨在提高代码的模块化、可维护性和可扩展性。

一、Ioc(控制反转)

        控制反转(Inversion of Control)是一种设计原则,用来减少计算机程序中的依赖关系,它允许程序在运行时动态地适应和配置对象之间的关系。在Java中,IoC通常通过依赖注入(DI)实现,其实就减少我们在业务层通过new 来创建dao层对象。

IoC的主要特点:

  • 依赖注入(DI):组件之间的依赖关系由容器在运行时注入,而不是在代码中硬编码。
  • 容器管理:容器负责创建对象、管理它们的生命周期和依赖关系。
  • 松耦合:由于依赖关系是在运行时注入的,因此组件之间的耦合度降低。

Spring框架中的IoC:

  • Spring使用IoC容器来管理应用程序中的对象,这些对象被称为Beans。
  • 通过@Autowired注解,Spring可以自动装配Bean的依赖关系。
  • 可以在XML配置文件或使用注解(如@Component@Service@Repository)来配置Bean。

二、Aop(面向切面编程)

        面向切面编程(Aspect Orient Programming)是一种编程范式,它允许程序员将横切关注点(如日志记录、事务管理、安全性等)与业务逻辑分离,从而提高代码的模块化和可维护性。

Aop的主要特点:

  • 切面:切面是封装横切关注点的模块,可以包含前置、后置、环绕和异常处理等通知。
  • 连接点:程序执行过程中的某些点(如方法调用),可以在这些点上应用切面。
  • 切点:定义了哪些连接点会被切面所通知。
  • 织入:将切面应用到目标对象上并创建新的代理对象的过程。

Spring框架中的Aop:

  • Spring AOP使用代理机制来实现AOP,可以在不修改目标对象的情况下增加额外的行为。
  • 支持使用XML或注解(如@Aspect@Before@After@Around)来配置切面。
  • Spring AOP主要支持方法级别的切点。

Aop常用注解:

  • @Aspect: 将一个类标识为一个切面(Aspect),这意味着这个类包含切面逻辑。
  • @Before:前置通知,在目标方法执行之前执行。
  • @After:后置通知,在目标方法执行之后执行,无论目标方法是否抛出异常。
  • @AfterReturning:返回通知,在目标方法成功执行后执行,即目标方法返回结果后。
  • @AfterThrowing:异常通知,在目标方法抛出异常后执行。
  • @Around:环绕通知,可以包裹目标方法的执行,拥有最大的控制权,可以在目标方法执行前后执行自定义逻辑。

三、Aop和Ioc的关系

在Spring框架中,AOP和IoC是紧密集成的:

  • IoC容器提供基础:Spring的IoC容器负责管理Bean的生命周期和依赖关系,为AOP提供运行时的对象。
  • AOP在IoC基础上工作:Spring AOP使用IoC容器中的对象来创建代理,并将切面织入到这些对象中。
  • 无缝集成:Spring允许你在IoC容器中声明Bean的同时声明它们为切面,并配置它们的织入点。

四、代码示例

Ioc代码示例

        1. 创建接口

package com.demo.aop.ioc;
/**
 * 文件名:DemoService
 * 创建者:宁贝贝
 * 创建时间:2024-08-20
 * 描述:
 */
public interface DemoService {
    void display();
}

        2. 实现接口

package com.demo.aop.ioc;
/**
 * 文件名:DemoServiceImpl
 * 创建者:
 * 创建时间:2024-08-20
 * 描述:
 */
public class DemoServiceImpl implements DemoService{
    @Override
    public void display() {
        System.out.println("此方法被调用。。");
    }
}

        3. 通过配置类将类加载至容器

package com.demo.aop.ioc;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
 * 文件名:DemoConfig
 * 创建者:
 * 创建时间:2024-08-20
 * 描述:通过这个配置类创建一个DemoService对象
 */
@Configuration
@ComponentScan(basePackages = "com.demo.aop.ioc")
public class DemoConfig {

    @Bean(value = "demoService") //这个注解主要是设置容器中对象的名称,(如果不设置默认的是首字母小写类名称)
    public DemoService DemoService() {
        return new DemoServiceImpl();
    }
}

        4. 测试类

package com.demo.aop.ioc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
 * 文件名:IocDemo
 * 创建者:
 * 创建时间:2024-08-20
 * 描述:
 */
public class IocDemo {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);
        // 获取demoService的Bean
        DemoService demoService = context.getBean("demoService", DemoService.class);
        demoService.display();
    }
}
Aop代码示例

        1. 创建业务接口

package com.demo.aop;

/**
 * 文件名:MathService
 * 创建者:
 * 创建时间:2024-08-20
 * 描述: 业务接口
 */
public interface MathService {
    int add(int a, int b);
}

        2. 业务实现类

package com.demo.aop;

/**
 * 文件名:MathServiceImpl
 * 创建者:
 * 创建时间:2024-08-20
 * 描述:
 */
public class MathServiceImpl implements MathService {
    @Override
    public int add(int a, int b) {
        int sum = a+b;
        System.out.println("执行计算方法  "+ sum);
        return sum;
    }
}

        3. 创建配置类将bean交给容器管理

package com.demo.aop;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * 文件名:AopConfig
 * 创建者:
 * 创建时间:2024-08-20
 * 描述: EnableAspectJAutoProxy 开启aop
 */
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.demo.aop")
public class AopConfig {
    @Bean(value = "mathService") //这个注解主要是设置容器中对象的名称,(如果不设置默认的是首字母小写类名称)
    public MathService BusServiceImpl() {
        return new MathServiceImpl();
    }
}

        4. 创建切面类

package com.demo.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
 * 文件名:LoggingAspect
 * 创建者:宁贝贝
 * 创建时间:2024-08-20
 * 描述:
 */
@Aspect
@Component
public class LoggingAspect {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * @Pointcut注解定义了一个切点,用于匹配com.example.service包下所有类的所有方法
     */
    @Pointcut("execution(* com.demo.aop.MathService.add(..))")
    public void logOnMathServiceAdd() {}
    /**
     * @Before 注解的关键属性:
     *     value 或 pointcut:指定切点表达式,用于匹配哪些方法的执行将触发通知。如果不指定 value,则通知将应用于所有方法。
     *     joinPoint:方法参数,表示当前的连接点(例如,被通知的方法),可以用于获取方法签名、参数等信息。
     *     其他可选参数包括 argNames(指定方法参数的名称以匹配特定的参数值)等。
     * @param joinPoint
     */
    @Before("logOnMathServiceAdd()")
    public void logBeforeAddition(JoinPoint joinPoint) {
        logger.info("前置方法 {},{}", joinPoint.getArgs()[0],joinPoint.getArgs()[1]);
    }
    /**
     * @AfterReturning注解的关键属性:
     *     value 或 pointcut:指定切点表达式,用于匹配哪些方法的执行将触发通知。如果不指定value,则通知将应用于所有方法。
     *     returning:用于指定方法返回值的参数名称。在通知方法中,可以使用此参数名称来引用方法的返回值。
     * @param joinPoint
     * @param result
     */
    @AfterReturning(pointcut = "logOnMathServiceAdd()", returning = "result")
    public void logAfterAdditionReturning(JoinPoint joinPoint, Object result) {
        logger.info("后置方法{},{},{}", joinPoint.getArgs()[0], joinPoint.getArgs()[1], result);
    }
}

        5. 创建测试类

package com.demo.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 文件名:AopDemo
 * 创建者:
 * 创建时间:2024-08-20
 * 描述:
 */
public class AopDemo {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
        // 获取MathService的Bean
        MathService mathService = context.getBean("mathService", MathService.class);
        mathService.add(2, 3);
    }
}

        6. 执行结果

五、总结

        通过结合使用AOP和IoC,Spring框架提供了一种强大的方式来构建松耦合、易于测试和维护的应用程序。AOP允许开发者将业务逻辑与横切关注点分离,而IoC则简化了组件之间的依赖管理和配置。

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值