Spring中的IOC和AOP


一、什么是Spring

spring的核心概念:

Spring 框架是一款轻量级的开发框架,核心思想是 IOC(控制反转)和 AOP(面向切面编程)。为 Java 应用程序开发提供组件管理服,用于组件之间的解耦,以及简化第三方JavaEE中间件技术的使用(IMS、任务调度、缓存、ORM 框架),是一个基础架构型的开发框架;。


二、IOC(控制反转)

什么是IOC?
IOC(Inversion of Control,控制反转)是Spring框架的核心思想之一。传统的程序设计中,对象的创建和依赖关系的管理是由程序员手动完成的。而在Spring中,对象的创建和依赖关系的管理交给了Spring容器来处理,这就是所谓的“控制反转”。

1、IOC的实现方式

Spring通过依赖注入(Dependency Injection, DI)来实现IOC。依赖注入是指Spring容器在运行时将对象所依赖的其他对象自动注入到目标对象中,而不需要程序员手动去创建和管理这些依赖关系。

2、代码示例

在Spring中,我们可以通过依赖注入来实现:构造注入或者set注入

// 通过构造函数注入
public class IStudentServiceImp implements IStudentService {
	
    IStudentDao dao ;	
    public IStudentServiceImp(IStudentDao dao) {
        this.dao = dao;
    }
   public void save() {
        System.out.println("这是service的save方法");
        dao.save();
    }
}

//set注入
public class IStudentServiceImp implements IStudentService {

    IStudentDao dao ;
    public void setDao(IStudentDao dao) {
        this.dao = dao;
    }
    public void save() {
        System.out.println("这是service的save方法");
        dao.save();
    }
}

然后在Spring的配置文件中(如applicationContext.xml)进行配置:

<bean id="IStudentDaoImp" class="com.apesource.dao.IStudentDaoImp"></bean>
    <bean id="IStudentServiceImp" class="com.apesource.service.IStudentServiceImp">
        <constructor-arg index="0" ref="IStudentDaoImp"></constructor-arg>
</bean>
 <bean id="IStudentDaoImp" class="com.apesource.dao.IStudentDaoImp"></bean>
    <bean id="IStudentServiceImp" class="com.apesource.service.IStudentServiceImp">
        <property name="dao" ref="IStudentDaoImp"></property>
 </bean>

3、IOC 的应用场景

1. 依赖注入(DI)
场景: 对象之间的依赖关系由容器动态注入,而不是在代码中硬编码。
示例: 在Spring中,使用@Autowired注解自动注入依赖对象。
2. 模块化开发
场景: 在大型项目中,模块之间的依赖关系复杂,需要解耦。
示例: 将服务层、数据层、控制层分离,通过IOC容器动态组装。
3. 单例模式管理
场景: 需要确保某些对象在应用中只存在一个实例。
示例: 在Spring中,默认的Bean作用域是单例(Singleton)。
4. 配置管理
场景: 将配置信息(如数据库连接、API密钥)从代码中分离,集中管理。
示例: 在Spring中,使用@Value注解注入配置文件中的值。
5. 测试驱动开发(TDD)
场景: 在单元测试中,需要模拟依赖对象。
示例: 使用Mockito等工具创建模拟对象,并通过IOC容器注入到被测试对象中。
6. 事务管理
场景: 在数据库操作中,需要统一管理事务。
示例: 在Spring中,使用@Transactional注解管理事务。


三、AOP(面向切面编程)

1、什么是AOP?

AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它允许开发者将横切关注点(如日志记录、事务管理、安全性等)从业务逻辑中分离出来。通过AOP,开发者可以在不修改原有代码的情况下,为程序动态地添加功能。

2、AOP的核心概念

切面(Aspect):一个模块化的横切关注点,通常是一个类,包含了一些通知和切点。
通知(Advice):在切面的某个特定连接点上执行的动作。常见的通知类型有:前置通知(Before)、后置通知(After)、返回通知(After-returning)、异常通知(After-throwing)和环绕通知(Around)。
切点(Pointcut):定义了在哪些连接点上应用通知。
连接点(Joinpoint):程序执行过程中的某个特定点,如方法调用或异常抛出。

3、核心概念代码示例

这里我们定义了一个工具类Logger模拟AOP的几个通知:
工具类代码

import org.aspectj.lang.ProceedingJoinPoint;

public class Logger {

    public void beforeMethod(){
        System.out.println("执行方法时的前置通知");
    }

    public void returnMethod(){
        System.out.println("执行方法时的返回通知");
//        int i = 1/0;
    }
    public void exceptionMethod(){
        System.out.println("执行方法时的异常通知");
    }
    public void afterMethod(){
        System.out.println("执行方法时的后置通知");
    }

    public Object aroundMethod(ProceedingJoinPoint pjp){

        Object object = null;

        try {
            System.out.println("环绕通知的前置通知");
            object = pjp.proceed(pjp.getArgs());
            System.out.println("环绕通知的返回通知");
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println("环绕通知的异常通知");
        }finally {
            System.out.println("环绕通知的后置通知");
        }
        return object;
    }
}

配置类文件

<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"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
        
    <!--注入业务层-->
    <bean id="accountServiceImp" class="com.apesource.service.AccountServiceImp"></bean>
    <!--注入日志记录层(通知)-->
    <bean id="logger" class="com.apesource.util.Logger"></bean>

    <!--配置AOP-->
    <aop:config>
        <!--配置切面 -->
        <aop:aspect id="aopAspect" ref="logger">
            <!--切点-->
            <aop:pointcut id="pointCut" expression="execution(* com.apesource.service.*.*(..))"></aop:pointcut>
            <!--前置通知-->
           <!-- <aop:before method="beforeMethod" pointcut-ref="pointCut"></aop:before>-->
            <!--返回通知-->
            <!-- <aop:after-returning method="returnMethod" pointcut-ref="pointCut"></aop:after-returning>-->
            <!--异常通知-->
            <!-- <aop:after-throwing method="exceptionMethod" pointcut-ref="pointCut"></aop:after-throwing>-->
            <!--后置通知-->
            <!-- <aop:after method="afterMethod" pointcut-ref="pointCut"></aop:after>-->

            <aop:around method="aroundMethod" pointcut-ref="pointCut"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>

业务层代码

public interface IAccountService {

	public void save(int i);
    public void update();
    public void delete();
    
}

public class AccountServiceImp implements IAccountService {

    public void save(int i) {
        System.out.println("执行service的save方法"+i);
    }
    public void update() {
        System.out.println("执行service的update方法");
    }
    public void delete() {
        System.out.println("执行service的delete方法");
    }
}

测试类代码

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class Test01 {

    @Autowired
    public IAccountService service;

    @Test
    public void show(){
//      service.save(1);
        service.update();
    }
}

4、AOP的实现

AOP的实现的实现基于动态代理实现,有两种方式:
1、JDK动态代理:基于接口实现,要求目标类必须实现接口。
使用java.lang.reflect.Proxy类创建代理对象。
2、CGLIB动态代理:基于子类实现,不要求目标类实现接口。
使用net.sf.cglib.proxy.Enhancer类创建代理对象。

5、动态代理代码示例

JDK实现:
接口和实现类

public interface ISinger {
    public void sing();
}
public class ZhouJieLun implements ISinger {
    public void sing() {
        System.out.println("===来一首花海===");
    }
}

测试类代码

public class Test {
    public static void main(String[] args) {
        //被代理对象
        final ISinger zJL = new ZhouJieLun();
      
        ISinger  proxy = (ISinger) Proxy.newProxyInstance(zJL.getClass().getClassLoader(), zJL.getClass().getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //增强代码
                System.out.println("喝完茶在唱歌");
                Object object = method.invoke(zJL,args);
                return object;
            }
        });
        proxy.sing();
    }
}

CGLIB实现

public interface ISinger {
    public void sing();
}

public class ZhouJieLun implements ISinger {
    public void sing() {
        System.out.println("===天青色等烟雨而我在等你===");
    }
}

测试类代码

public class Test {
    public static void main(final String[] args) {
        //被代理对象
        final ISinger zJL = new ZhouJieLun();
        ISinger daiLi = (ISinger) Enhancer.create(zJL.getClass(), new InvocationHandler() {
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                Object obj = method.invoke(zJL,args);
                return obj;
            }
        });
        daiLi.sing();
    }

6、AOP的应用场景

1. 日志记录
场景: 在方法执行前后记录日志,便于调试和监控。
示例: 使用AOP在方法执行前后自动记录日志。
2. 权限控制
场景: 在方法执行前进行权限验证。
示例: 使用AOP在方法调用前自动检查用户权限。
3. 性能监控
场景: 监控方法执行时间,识别性能瓶颈。
示例: 使用AOP在方法执行前后记录时间,自动计算执行时长。
4. 缓存管理
场景: 在方法执行前检查缓存,存在则直接返回,避免重复计算。
示例: 使用AOP在方法调用前自动检查缓存。
5. 异常处理
场景: 统一处理系统中的异常,避免重复代码。
示例: 使用AOP在方法抛出异常时自动捕获并处理。
6. 事务管理
场景: 在数据库操作中确保事务的原子性。
示例: 使用AOP在方法执行前后自动管理事务。

四、总结AOP 和 IOC 结合使用的好处

降低代码耦合度,提升模块化。
提升代码复用性,减少重复代码。
简化开发流程,提高开发效率。
增强可维护性,便于修改和调整。
提高系统灵活性,支持动态调整。
统一管理横切关注点,提升代码可读性。
支持声明式编程,简化复杂功能实现。
增强测试能力,提升测试覆盖率。
提升系统性能,优化资源使用。
简化复杂功能实现,降低开发难度。
通过结合使用AOP和IOC,开发者可以更高效地构建灵活、可维护和高性能的应用系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值