`
pi88dian88
  • 浏览: 40696 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

简单记录spring 实现IOC的流程

阅读更多

IOC: Inversion of Control, 指由spring容器来生成对象并且完成对象的装配。

 

下面来看下这两个问题:(下面是以 ClassPathXmlApplicationContext为起点)

1, spring如何生成对象?

2, spring如何完成对象组装?

 

完成这个的核心是通过BeanFactory,下面是BeanFactory的代码:

public interface BeanFactory {	
	String FACTORY_BEAN_PREFIX = "&";

	Object getBean(String name) throws BeansException;

	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	<T> T getBean(Class<T> requiredType) throws BeansException;

	Object getBean(String name, Object... args) throws BeansException;

	boolean containsBean(String name);

	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;

	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	String[] getAliases(String name);
}

 从上面可知,如果有了BeanFactory,就可以通过getBean的方法去获取想要的对象,后面组装的事情也就顺理成章了。

 

下面是简单的spring的demo,代码可以通过附件下载,部分测试代码如下:

public class SpringDemo {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:/beans.xml");
		AppleService appleService = context.getBean("appleService", AppleService.class);
		Apple apple = appleService.createApple();
		System.out.println(apple);
	}
}

 

代码的入口从ClassPathXmlApplicationContext开始,下面是ClassPathXmlApplicationContext的代码:

public ClassPathXmlApplicationContext(String[] paths, Class clazz, ApplicationContext parent)
			throws BeansException {
		super(parent);
		Assert.notNull(paths, "Path array must not be null");
		Assert.notNull(clazz, "Class argument must not be null");
		this.configResources = new Resource[paths.length];
		for (int i = 0; i < paths.length; i++) {
			this.configResources[i] = new ClassPathResource(paths[i], clazz);
		}
		refresh();
	}

调用父类AbstractApplicationContext的refresh方法,

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
		}
	}

 在obtainFreshBeanFactory方法中,创建DefaultListableBeanFactory,然后通过DocumentBuilderFactory将spring配置文件转成Document对象,然后根据不同的节点名进行处理,解析元素代码如下:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
                //IMPORT_ELEMENT = "import"
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
                //ALIAS_ELEMENT = "alias"
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
                //BEAN_ELEMENT="bean"
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
                //NESTED_BEANS_ELEMENT = "beans"
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

 以bean节点解析为例,看下parseBeanDefinitionElement的方法

 

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
                //解析bean节点
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
                                //将BeanDefinition注册到BeanFactory中(后面有解释)
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

 下面是调用BeanDefinitionParserDelegate的parseBeanDefinitionAttributes方法,将xml配置的bean的属性(lazy-init, scope, destroy-method等属性)设置到BeanDefinition中。

 

 

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
			BeanDefinition containingBean, AbstractBeanDefinition bd) {

		if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
			// Spring 2.x "scope" attribute
			bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
			if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
				error("Specify either 'scope' or 'singleton', not both", ele);
			}
		}
		else if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
			// Spring 1.x "singleton" attribute
			bd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ?
					BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE);
		}
		else if (containingBean != null) {
			// Take default from containing bean in case of an inner bean definition.
			bd.setScope(containingBean.getScope());
		}

		if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
			bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
		}

		String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
		if (DEFAULT_VALUE.equals(lazyInit)) {
			lazyInit = this.defaults.getLazyInit();
		}
		bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

		String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
		bd.setAutowireMode(getAutowireMode(autowire));

		String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
		bd.setDependencyCheck(getDependencyCheck(dependencyCheck));

		if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
			String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
			bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
		}

		String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
		if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
			String candidatePattern = this.defaults.getAutowireCandidates();
			if (candidatePattern != null) {
				String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
				bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
			}
		}
		else {
			bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
		}

		if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
			bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
		}

		if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
			String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
			if (!"".equals(initMethodName)) {
				bd.setInitMethodName(initMethodName);
			}
		}
		else {
			if (this.defaults.getInitMethod() != null) {
				bd.setInitMethodName(this.defaults.getInitMethod());
				bd.setEnforceInitMethod(false);
			}
		}

		if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
			String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
			if (!"".equals(destroyMethodName)) {
				bd.setDestroyMethodName(destroyMethodName);
			}
		}
		else {
			if (this.defaults.getDestroyMethod() != null) {
				bd.setDestroyMethodName(this.defaults.getDestroyMethod());
				bd.setEnforceDestroyMethod(false);
			}
		}

		if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
			bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
		}
		if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
			bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
		}

		return bd;
	}

 在上面的processBeanDefinition方法中,解析完某个节点,生成BeanDefinition时,会调用BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())方法,然后向BeanFactory注册该BeanDefinition对象,代码如下:

 

 

//DefaultListableBeanFactory.java
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		...
		synchronized (this.beanDefinitionMap) {
			Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
			if (oldBeanDefinition != null) {
				if (!this.allowBeanDefinitionOverriding) {
					throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
							"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
							"': There is already [" + oldBeanDefinition + "] bound.");
				}
			}
			else {
				this.beanDefinitionNames.add(beanName);
				this.frozenBeanDefinitionNames = null;
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}

		resetBeanDefinition(beanName);
	}

 然后重新回到AbstractApplicationContext的refresh方法,调用invokeBeanFactoryPostProcessors(spring提供了BeanFactoryPostProcessor扩展点,可以通过实现BeanFactoryPostProcess来初始化某些参数),再通过调用refresh方法中的finishBeanFactoryInitialization来完成对象的创建。代码如下:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
                //创建并且组装对象
		beanFactory.preInstantiateSingletons();
	}

然后进入DefaultListableBeanFactory的preInstantiateSingletons方法,代码如下,beanDefinitionMap存放的是前面解析配置文件得到的<beanName, BeanDefinition>的map数据。

public void preInstantiateSingletons() throws BeansException {
		...
		List<String> beanNames;
		synchronized (this.beanDefinitionMap) {
			// Iterate over a copy to allow for init methods which in turn register new bean definitions.
			// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
			beanNames = new ArrayList<String>(this.beanDefinitionNames);
		}
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
							public Boolean run() {
								return ((SmartFactoryBean<?>) factory).isEagerInit();
							}
						}, getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
				else {
					getBean(beanName);
				}
			}
		}
	}

 在getBean方法中,会调用AbstractBeanFactory的doGetBean来创建对象,方法如下:

protected <T> T doGetBean(
			final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
			throws BeansException {
                ...
		if (mbd.isSingleton()) {
			sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
				public Object getObject() throws BeansException {
					try {
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						// Explicitly remove instance from singleton cache: It might have been put there
						// eagerly by the creation process, to allow for circular reference resolution.
						// Also remove any beans that received a temporary reference to the bean.
						destroySingleton(beanName);
						throw ex;
					}
				}
			});
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
		}

		else if (mbd.isPrototype()) {
			// It's a prototype -> create a new instance.
			Object prototypeInstance = null;
			try {
				beforePrototypeCreation(beanName);
				prototypeInstance = createBean(beanName, mbd, args);
			}
			finally {
				afterPrototypeCreation(beanName);
			}
			bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
		}
                ...
		return (T) bean;
	}

 在createBean中,会调用AbstractAutowireCapableBeanFactory的doCreateBean方法,代码如下:(这个方法显示了对象的创建以及后续初始化的流程

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
                //实例化对象
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
                               //调用BeanPostProcessor处理
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, new ObjectFactory() {
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
                        //设置bean的参数(通过property标签配置)
			populateBean(beanName, mbd, instanceWrapper);
			if (exposedObject != null) {
                                //调用init-method
				exposedObject = initializeBean(beanName, exposedObject, mbd);
			}
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		...
		return exposedObject;
	}

 继续往下看createBeanInstance方法,通过调用instantiateBean实例化对象,代码如下:

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			final BeanFactory parent = this;
			if (System.getSecurityManager() != null) {
				beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
					public Object run() {
						return getInstantiationStrategy().instantiate(mbd, beanName, parent);
					}
				}, getAccessControlContext());
			}
			else {
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
			}
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}

 InstantiationStrategy有两种,SimpleInstantiationStrategy和CglibSubclassingInstantiationStrategy。关系如下:

 

spring对CglibSubclassingInstantiationStrategy的使用场景注释:Using Method Injection features requires CGLIB on the classpath. However, the core IoC container will still run without CGLIB being available.

下面再来看SimpleInstantiationStrategy的instantiate方法,代码如下:

public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if (beanDefinition.getMethodOverrides().isEmpty()) {
			Constructor<?> constructorToUse;
			synchronized (beanDefinition.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class clazz = beanDefinition.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
								public Constructor run() throws Exception {
									return clazz.getDeclaredConstructor((Class[]) null);
								}
							});
						}
						else {
							constructorToUse =	clazz.getDeclaredConstructor((Class[]) null);
						}
						beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Exception ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass.
			return instantiateWithMethodInjection(beanDefinition, beanName, owner);
		}
	}

 通过上面的流程,这样对象的创建就完成了。

 

受篇幅所限,只是介绍了对象的生成,对象的装配具体过程,下篇来写了~


 

 

 

 

  • 大小: 13 KB
0
0
分享到:
评论

相关推荐

    Spring-ioc-jar

    6. **AOP代理**: Spring的IOC容器与AOP框架紧密集成,可以为Bean创建代理对象,实现切面编程,如事务管理、日志记录等。 7. **资源管理**: Spring容器还可以管理其他的资源,比如数据库连接、JMS消息等,提供统一的...

    Spring IOC.pdf

    在Spring框架中,IOC具体体现在对依赖关系的管理上,使得对象的创建、依赖关系的绑定等过程不再由应用程序自身完成,而是转移到一个外部容器(IoC容器)中进行管理,这样就实现了控制权的反转。 首先,Spring IoC...

    spring ioc+mvc代码

    本文将通过分析并实现一个简化版的Spring IOC+MVC框架,帮助读者深入理解这两个核心概念以及Spring的工作原理。 一、Spring IOC(Inversion of Control)——控制反转 控制反转,简称IOC,是Spring框架的核心特性...

    Spring-IoC.rar_容器

    - **AOP(面向切面编程)**:Spring提供了一套完整的AOP支持,允许开发者定义拦截器,实现日志记录、事务管理等功能。 - **事件发布**:Spring容器支持事件发布和监听机制,允许bean之间进行通信,而无需直接引用...

    Spring4Ioc-Aop

    ### Spring4 Ioc-Aop 知识点详解 #### 一、Spring框架简介 Spring是一个开源框架,旨在简化企业级应用开发。通过Spring框架,普通的JavaBean能够实现以往只有通过EJB才能完成的功能。Spring的核心特性包括轻量级、...

    Spring框架的流程

    7. **IoC(控制反转)**:Spring通过IoC管理对象的生命周期和依赖关系,对象的创建和装配由Spring容器负责,而不是由对象自身来完成,这降低了组件间的耦合度。 8. **Spring的启动**:在应用程序启动时,Spring容器...

    spring工作流程

    Spring允许开发者定义切入点(Pointcuts)、切面(Advice)和其他AOP术语,然后在运行时根据这些定义动态地生成代理类,从而实现特定的关注点(如日志记录或事务管理)。 综上所述,Spring框架通过其强大的IoC和AOP...

    Spring-IoC-Learning:手动实现IoC容器

    在本文中,我们将探讨Spring IoC的基本概念、工作流程,并尝试手动实现一个简单的IoC容器。 首先,了解IoC的概念至关重要。IoC是一种设计模式,它将对象的创建和管理权从代码中分离出来,转交给一个外部容器(即IoC...

    Spring基础:IoC容器(2)

    Spring的IoC容器主要有两种实现:BeanFactory和ApplicationContext。BeanFactory是最基本的容器,提供了完整的IoC功能,而ApplicationContext在此基础上增加了更多的企业级服务,如消息资源、国际化支持等。在实际...

    day-Spring IoC & DI.md

    - **方便解耦,简化开发**:Spring 通过其提供的 IOC 容器,帮助开发者实现组件间的解耦。对象之间的依赖关系由 Spring 进行管理,避免了硬编码带来的耦合问题。开发者可以更加专注于业务逻辑的实现。 - **AOP ...

    spring源码分析流程全面解析

    Spring的核心是IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入),这些机制使得应用程序的组件之间松耦合,便于测试和维护。 标题中的"spring源码分析流程全面解析"指的是对Spring...

    hibernate+struts2+spring实现添删改查

    通过Spring的IoC容器,我们可以声明性地配置和管理这些组件,使得代码更加解耦和易于测试。同时,Spring Data JPA模块可以进一步简化与Hibernate的交互,提供更高级别的数据访问API。 当这三者结合使用时,Struts2...

    SpringIOC和AOP原理设计模式

    此外,Spring使用了一些设计模式,如简单工厂、工厂方法和单例模式,来实现对象的创建和管理。 **Spring AOP原理与实现方式** 面向切面编程(AOP)是Spring框架的另一大特色,它允许开发者将横切关注点(如日志、...

    论坛系统 Struts2+Hibernate+Spring实现

    此外,Spring的AOP特性可以方便地实现日志记录、权限控制等功能。在论坛系统中,Spring可以用来管理用户会话、实现权限控制,以及处理业务逻辑。 **Hibernate** 是一个对象关系映射(ORM)框架,它将数据库操作转化...

    struts2+spring+mybatis框架

    同时,Spring的AOP模块可以用于实现如日志记录、权限控制等通用功能。 **MyBatis框架** MyBatis是一个优秀的持久层框架,它允许开发者编写SQL语句并与Java代码进行深度融合。MyBatis消除了几乎所有的JDBC代码和参数...

    struts2与spring实现简单登陆

    2. **Spring框架**:Spring的核心是IoC(Inversion of Control,控制反转)和AOP(Aspect-Oriented Programming,面向切面编程)。IoC通过容器管理对象的依赖关系,降低了代码间的耦合度;AOP则允许我们在不修改原有...

Global site tag (gtag.js) - Google Analytics