我的理解:一开始各个对象之间相互合作,是多个对象对应多个对象去使用,如果有一个对象出现问题就可能影响到全局,但是使用ioc就是在两者之间加入了一个中间媒介(spring bean也就是通过xml配置文件装配对象),如果相互需要,调用中间媒介即可,做到了极大的解耦。带来的问题是配置多运行效率就会降低。
什么是IOC?_贾州的博客-CSDN博客
控制反转名字的由来:
对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。
依赖注入:
public class OrderService {
private PaymentService paymentService;
// 通过构造函数注入依赖
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void processOrder(double amount) {
// 使用注入的 PaymentService 对象进行支付处理
paymentService.pay(amount);
// 其他订单处理逻辑...
}
}
public interface PaymentService {
void pay(double amount);
}
public class PayPalPaymentService implements PaymentService {
public void pay(double amount) {
// 使用 PayPal 的支付逻辑进行支付
// ...
}
}
OrderService 类依赖于 PaymentService 接口来处理支付逻辑。OrderService通过自身构造函数注入PaymentService ,OrderService 不需要直接依赖于具体的支付服务实现类,而是通过接口进行依赖,并且在运行时由外部容器负责创建和注入具体的 PaymentService 实例。这就是在应用了依赖注入后,控制反转的过程。OrderService 将自身对于 PaymentService 的控制权转移到了外部容器,外部容器负责创建和注入所需的具体实现类的实例。具体的实现由PaymentService 的实现类去实现具体功能。
AOP核心思想理解:目标方法在执行前后做一些日志或者安全检测
假设我们有一个简单的账户管理系统,其中包含一个AccountService接口和其实现类AccountServiceImpl,并且我们希望在每个方法执行前后记录日志。
首先,我们需要引入一个AOP框架,比如AspectJ或Spring AOP。这里我使用Spring AOP来实现AOP的示例。
// 定义AccountService接口
public interface AccountService {
void createAccount(String username);
void deleteAccount(String username);
}
// AccountService接口的实现类
public class AccountServiceImpl implements AccountService {
@Override
public void createAccount(String username) {
// 创建账户的具体逻辑
System.out.println("创建账户:" + username);
}
@Override
public void deleteAccount(String username) {
// 删除账户的具体逻辑
System.out.println("删除账户:" + username);
}
}
接下来,我们创建一个切面类LoggingAspect来定义日志记录的横切逻辑。
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.AccountService.*(..))")
public void beforeMethodExecution(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Before executing method: " + methodName);
}
@After("execution(* com.example.AccountService.*(..))")
public void afterMethodExecution(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("After executing method: " + methodName);
}
}
在上述代码中,我们使用了@Aspect注解和切点表达式来定义切面,@Before注解表示在目标方法执行前执行横切逻辑,@After注解表示在目标方法执行后执行横切逻辑。
最后,我们需要在Spring配置文件中配置AOP和Bean。
<beans xmlns="[http://www.springframework.org/schema/beans](http://www.springframework.org/schema/beans)"
xmlns:context="[http://www.springframework.org/schema/context](http://www.springframework.org/schema/context)"
xmlns:aop="[http://www.springframework.org/schema/aop](http://www.springframework.org/schema/aop)"
xsi:schemaLocation="[http://www.springframework.org/schema/beans](http://www.springframework.org/schema/beans)
[http://www.springframework.org/schema/beans/spring-beans.xsd](http://www.springframework.org/schema/beans/spring-beans.xsd)
[http://www.springframework.org/schema/context](http://www.springframework.org/schema/context)
[http://www.springframework.org/schema/context/spring-context.xsd](http://www.springframework.org/schema/context/spring-context.xsd)
[http://www.springframework.org/schema/aop](http://www.springframework.org/schema/aop)
[http://www.springframework.org/schema/aop/spring-aop.xsd](http://www.springframework.org/schema/aop/spring-aop.xsd)">
<!-- 开启Spring的注解支持 -->
<context:annotation-config />
<!-- 启用AOP -->
<aop:aspectj-autoproxy />
<!-- 扫描切面类 -->
<context:component-scan base-package="com.example" />
<!-- 配置AccountService的Bean -->
<bean id="accountService" class="com.example.AccountServiceImpl" />
</beans>
现在,当我们调用AccountService接口的方法时,AOP会自动在方法执行前后记录日志。例如:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService accountService = context.getBean(AccountService.class);
accountService.createAccount("John"); // 输出:Before executing method: createAccount
// 创建账户:John
// After executing method: createAccount
accountService.deleteAccount("John"); // 输出:Before executing method: deleteAccount
// 删除账户:John
// After executing method: deleteAccount
}
}
通过使用AOP,我们可以在不修改业务逻辑的情况下,将共享的横切关注点(日志记录)与核心业务逻辑(创建和删除账户)分离开来,提高代码的可维护性和可重用性。
AOP应用场景:
AOP(Aspect-Oriented Programming)是一种编程范式,通过将横切关注点(cross-cutting concerns)与核心业务逻辑分离,以模块化的方式实现共享和重用。在AOP中,横切关注点指的是在一个应用程序中散布于各个模块的功能,如日志记录、安全性、事务管理等。
下面是几个常见的AOP的应用场景的例子:
- 日志记录:通过AOP可以很方便地在关键方法执行前后记录日志,而不需要在每个方法中编写重复的日志记录代码。例如,可以使用AOP在每个方法执行前打印方法名、参数和执行时间。
- 安全性:通过AOP可以实现对方法或资源的访问控制。例如,可以使用AOP实现基于角色的访问控制,在方法执行前检查当前用户是否具有足够的权限来执行该方法。
- 事务管理:通过AOP可以实现声明性事务管理,将事务管理逻辑从业务逻辑中分离出来。例如,可以使用AOP在方法执行前开启事务,在方法执行后根据执行结果提交或回滚事务。
- 缓存管理:通过AOP可以实现自动缓存功能,将缓存逻辑从业务逻辑中解耦。例如,可以使用AOP在方法执行前检查是否存在缓存结果,如果存在则直接返回缓存值,否则执行方法并将结果添加到缓存中。
- 异常处理:通过AOP可以统一处理方法抛出的异常,在一处地方捕获和处理异常,而不需要在每个方法中编写繁琐的异常处理代码。例如,可以使用AOP在方法执行时捕获异常并进行统一的日志记录或错误处理。
依赖注入三种方式:
构造函数注入:
public class UserService {
private UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 使用userRepository进行相关操作的方法
}
set注入:向外部提供的是set方法
public class UserService {
private UserRepository userRepository;
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 使用userRepository进行相关操作的方法
}
接口注入:接口注入其实实现类也是用的set方法,向外部提供的是一个接口
public interface UserRepositoryAware {
void setUserRepository(UserRepository userRepository);
}
public class UserService implements UserRepositoryAware {
private UserRepository userRepository;
@Override
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 使用userRepository进行相关操作的方法
}