目录
Spring IoC
IoC的设计与实现
简单容器BeanFactory
高级容器ApplicationContext
IoC容器工作过程
Spring AOP
简单的Spring AOP示例
Spring IoC
IoC(Inversion of Control): IoC是一种设计原则,它反转了传统的控制流。
-
在传统的编程中,应用程序通常负责控制对象的创建和生命周期。
-
而在IoC中,控制权被反转,应用程序不再负责直接创建和管理对象,而是将这些职责委托给一个容器或框架。这个容器负责实例化、组装和管理对象,使得应用程序的组件更加解耦、可维护和可扩展。
IoC的设计与实现
Spring Ioc容器的设计中,可以看到两个主要的容器系列:简单容器BeanFactory和高级容器ApplicationContext。
简单容器BeanFactory
简单模拟下BeadFactory演示IoC的设计:
-
创建配置文件,包含BeanDefinition的信息。
user:com.elaine.myspring.ioc.beanfactory.bean.User
-
创建一个BeanDefinition类,定义bean的属性。
public class BeanDefinition { private String beanName; private Class beanClass; public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } public Class getBeanClass() { return beanClass; } public void setBeanClass(Class beanClass) { this.beanClass = beanClass; } }
-
创建资源加载器ResourceLoader,用来加载配置文件中的配置。
/** * 载入配置文件,通过BeanDefinition解析加载 */ public class ResourceLoader { public static Map<String, BeanDefinition> getResource() { Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(16); Properties properties = new Properties(); try { InputStream inputStream = ResourceLoader.class.getResourceAsStream("/beans.properties"); properties.load(inputStream); // 迭代遍历配置文件 Iterator<String> iterator = properties.stringPropertyNames().iterator(); while (iterator.hasNext()) { String key = iterator.next(); String className = properties.getProperty(key); BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setBeanName(key); Class clazz = Class.forName(className); beanDefinition.setBeanClass(clazz); // 加载资源 beanDefinitionMap.put(key, beanDefinition); } inputStream.close(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return beanDefinitionMap; } }
-
创建对象注册器BeanRegister,注册bean到container中。
public class BeanRegister { // 假设所有对象都是单例的,用一个单例map缓存 private Map<String, Object> singletonMap = new HashMap<>(); /** * 获取单例bean * @param beanName * @return */ public Object getSingletonBean(String beanName) { return singletonMap.get(beanName); } /** * 注册单例bean * @param beanName * @param bean */ public void registerSingletonBean(String beanName, Object bean) { if(singletonMap.containsKey(beanName)) { return; } singletonMap.put(beanName, bean); } }
-
创建对象工厂BeanFactory,初始化需要完成资源的加载,对象注册器的创建。
public class BeanFactory { private BeanRegister beanRegister; private Map<String, BeanDefinition> map = new HashMap<>(); public BeanFactory(){ // 创建bean注册器 beanRegister = new BeanRegister(); // 加载资源 this.map = new ResourceLoader().getResource(); } /** * 获取bean * @param beanName * @return */ public Object getBean(String beanName) { Object bean = beanRegister.getSingletonBean(beanName); if (bean != null) { return bean; } return createBean(map.get(beanName)); } /** * 创建bean * @param beanDefinition * @return */ private Object createBean(BeanDefinition beanDefinition) { try { Object bean = beanDefinition.getBeanClass().newInstance(); beanRegister.registerSingletonBean(beanDefinition.getBeanName(), bean); return bean; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } }
-
测试验证。
public class TestUser { @Test public void beanFactory() { BeanFactory beanFactory = new BeanFactory(); // 第一次获取,通过反射 User user = (User) beanFactory.getBean("user"); user.sayHello(); // 第二次获取,通过缓存 User user1 = (User) beanFactory.getBean("user"); user.sayHello(); // 所有对象都是单例的前提下,是同一个对象 System.out.println(user1 == user); } }
高级容器ApplicationContext
-
ApplicationContext继承自BeanFactory,拥有更多的功能和特性,包括国际化、事件传播、资源访问等。
-
和BeanFactory的延迟加载不同,ApplicationContext会在容器启动时就实例化和初始化所有的bean。
-
支持更丰富的配置方式,包括XML配置、注解、java配置等,并且支持自动扫描并注册bean。
ApplicationContext通过读取xml配置的形式获取bean:
public class MySpringApplication { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Product product = (Product) applicationContext.getBean("product"); System.out.println(product.getId()); } }
IoC容器工作过程
Spring 的 IOC 容器⼯作的过程,其实可以划分为两个阶段:容器启动阶段和Bean实例化阶段。
Spring AOP
AOP是Aspect-Oriented Programming(面向方面编程或面向切面)的简称,是一种编程范式,用于增强、扩展和管理应用程序的功能。
-
通过将交叉关注点(Cross-Cutting Concerns)从应用程序的主要业务逻辑中分离出来,实现了更好的模块化和可维护性。
-
通常包括日志记录、事务管理、安全性、异常处理等方面的功能。
简单的Spring AOP示例
1.项目中添加Spring AOP相关的依赖。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>5.3.27</version> </dependency>
2.创建一个目标类(Target Class),这是我们将应用AOP的类。
public class MyService { public void showTime() { System.out.println("Now :" + new Date(System.currentTimeMillis())); } public void sayHi() { System.out.println("Hi"); } }
3.创建一个切面类(Aspect Class),这是我们的AOP切面。
@Aspect public class LoggerAspect { public final static Logger logger = LoggerFactory.getLogger(LoggerAspect.class); /** * MyService类作为切点 */ @Pointcut("execution(* com.elaine.myspring.aop.service.MyService.*(..))") public void myLogger(){} @Before("myLogger()") public void doBefore() { logger.info("Before PointCut, say Hello!"); } @After("myLogger()") public void doAfter() { logger.info("After PointCut, say Bye!"); } }
4.配置文件配置AOP
<?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" 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="myService" class="com.elaine.myspring.aop.service.MyService" /> <!-- 配置切面 --> <bean id="loggingAspect" class="com.elaine.myspring.aop.aspect.LoggerAspect" /> <!-- 启用AOP自动代理 --> <aop:aspectj-autoproxy/> </beans>
5.调用方法
public class MySpringApplication { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); MyService service = (MyService) applicationContext.getBean("myService"); service.showTime(); service.sayHi(); } }
结果