`

Spring part 1:IoC和DI

阅读更多

 

 

http://repo.springsource.org/libs-release-local/

 

 

这是Spring所包含的模块,但随着Spring的发展壮大,模块也是越来越多


传统的实例化对象方式是,我需要什么对象,我来new,SpringIoC实例化对象的思想是,你需要什么对象?告诉我,我给你(注入)。

注入的方式有三种:接口注入、方法注入、构造注入

SpringIoC职责:对象的构建与管理、对象间依赖绑定

管理对象间依赖方式:编码、配置文件、注解(元数据)

 

导入所需要的底层4个核心jar包

spring-beans-3.2.5.RELEASE.jar
spring-context-3.2.5.RELEASE.jar
spring-core-3.2.5.RELEASE.jar
spring-expression-3.2.5.RELEASE.jar

还需要日志包

commons.logging-1.1.1.jar
log4j-1.2.15.jar

创建两个配置文件

log4j.properties
applictionContext.xml

 工程目录结构如下

 

案例1:创建一个实例对象,将该对象交由SpringIoC容器管理,通过SpringIoC容器为其初始化

public class InstanceBean {
	public InstanceBean() {
		System.out.println("...");
	}
	public void method() {
		System.out.println("InstanceBean--method()");
	}
}

在applicationContext.xml中配置InstanceBean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="instanceBean" class="ioc.InstanceBean"></bean>
</beans>

该配置文件中的schema可以通过官方文档找到,以Spring3.2.5为例

spring-framework-3.2.5.RELEASE\docs\spring-framework-reference\html\xsd-config.html

 该文档中有所有关于Spring配置的xml约束,bean的约束在xsd-config.html的最下方

使用SpringIoC容器初始化InstanceBean

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:ioc/applictionContext.xml");
InstanceBean instance = context.getBean("instanceBean", InstanceBean.class);
instance.getMethod();

我把applicationContext.xml放在了src下的ioc包中,所以路径前加上了“ioc/”,编译后的项目结构为

 

案例二:SpringIoC容器通过构造实例化对象,案例一中的方式是通过默认构造器实例化InstanceBean,也可以使用有参数的构造器实例化InstanceBean

public class InstanceBean {
	private String info;

	public InstanceBean() {
		System.out.println("..." + this);
	}

	public InstanceBean(String info) {
		this.info = info;
	}
}

 applicationContext.xml配置,采用index+value方式,index表示构造器中参数位置,value表示参数的值

<!-- 默认构造器 -->
	<bean id="instaceBean" class="ioc.InstanceBean">
	</bean>
	<!-- 指定构造器 -->
	<bean id="constructor" class="ioc.InstanceBean">
		<constructor-arg index="0" value="springIoC"></constructor-arg>
	</bean>

 案例三:静态工厂初始化

创建一个工厂类,有两个静态方法,一个使用默认构造器,一个使用有参数的构造器

public class StaticFactory {
	public static InstanceBean getInstanceBean() {
		return new InstanceBean();
	}
	public static InstanceBean getInstanceBeanPara(String info) {
		return new InstanceBean(info);
	}
}

 对静态工厂进行配置,使用SpringIoC初始化

<!-- 静态工厂 -->
	<bean id="staticFactory" class="ioc.StaticFactory" factory-method="getInstanceBean">
	</bean>
	<!-- 静态工厂 有参数 -->
	<bean id="staticFactoryParam" class="ioc.StaticFactory" factory-method="getInstanceBeanPara">
	<constructor-arg index="0" value="staticFacotryParam"></constructor-arg>
	</bean>

 

 测试

@Test
	public void testIoCStaticFactory() {
		ApplicationContext context = new ClassPathXmlApplicationContext("classpath:ioc/applicationContext.xml");
		InstanceBean instance = context.getBean("staticFactory",InstanceBean.class);
		instance.getMethod();
	}
	@Test
	public void testIoCStaticFactoryParam() {
		ApplicationContext context = new ClassPathXmlApplicationContext("classpath:ioc/applicationContext.xml");
		InstanceBean instance = context.getBean("staticFactoryParam",InstanceBean.class);
		System.out.println(instance.getInfo());
	}

 案例三:实例工厂

创建实例工厂类

public class InstanceFacotry {
	public InstanceBean getInstanceBean() {
		return new InstanceBean();
	}
}

 配置时需要先配置实例工厂,然后通过factory-bean引用实例工厂的id,通过factory-method指定调用实例工厂中的哪个方法

<!-- 实例工厂 -->
	<bean id="instanceFactory" class="ioc.InstanceFacotry"></bean>
	<bean id="insFactory" factory-bean="instanceFactory" factory-method="getInstanceBean"></bean>

案例四:setter注入

创建一个包含setter()的类

public class InstanceBean {
	private String info;

	public InstanceBean() {
		System.out.println("..." + this);
	}

	public String getInfo() {
		return this.info;
	}

	public void setInfo(String info) {
		this.info = info;
	}
}

配置

<!-- setter注入 -->
	<bean id="instanceBeanSetter" class="ioc.InstanceBean">
		<property name="info" value="setInfo()"></property>
	</bean>

案例五:集合注入

创建一个类,包含常用的集合容器,生成setter(),使用SpringIoC容器注集合容器的内容

public class CollectionBean {
	private String[] arr;
	private String[][] array;
	private List<String> list;
	private Set<Integer> set;
	private Properties properties;
	private Collection<String> collection;
	private Map<String, String> map;
}

配置集合注入

<!-- 集合注入 -->
	<bean id="collectionDI" class="ioc.CollectionBean">
		<!-- 一维数组 -->
		<property name="arr">
			<array>
				<value>arr1</value>
				<value>arr2</value>
			</array>
		</property>
		<!-- 二维数组 -->
		<property name="array">
			<array>
				<array>
					<value>array1</value>
				</array>
				<array>
					<value>array2</value>
				</array>
			</array>
		</property>
		<!-- List集合 -->
		<property name="list">
			<!-- value-type:可选,相当于泛型 -->
			<list value-type="java.lang.String" merge="default">
				<value>list1</value>
				<value>list2</value>
				<value>list3</value>
			</list>
		</property>
		<!-- Set集合 -->
		<property name="set">
			<set value-type="java.lang.Integer">
				<value>1</value>
				<value>2</value>
				<value>3</value>
			</set>
		</property>
		<!-- Properties -->
		<property name="properties">
			<props>
				<prop key="1">pop1</prop>
				<prop key="2">pop2</prop>
			</props>
		</property>
		<!-- Collection -->
		<property name="collection">
			<set value-type="java.lang.String">
				<value>collction1</value>
				<value>collction2</value>
				<value>collction3</value>
			</set>
		</property>
		<!-- Map集合 -->
		<property name="map">
			<map key-type="java.lang.String" value-type="java.lang.String">
				<!-- 复杂配置 -->
				<entry>
					<key>
						<value>key1</value>
					</key>
					<value>value1</value>
				</entry>
				<!-- 简化配置 -->
				<entry key="key2" value="value2"></entry>
			</map>
		</property>
	</bean>

案例六:depends-on配置,在依赖情况下,depends-on配置的bean要先与当前bean初始化,晚于当前bean销毁

创建Resources、Dependency两个类,Dependency依赖Resources

public class Resources {
	public Resources() {
		super();
		System.out.println("Resources Constructor() ");
	}
	public void init(){
		System.out.println("Resources init()");
	}
	public void destroy(){
		System.out.println("Resources destroy()");
	}
}
public class Dependency {
	Resources resources;
	public Dependency() {
		super();
		System.out.println("Dependency Constructor() ");
	}
	public void init() {
		System.out.println("Dependency init()");
	}
	public void destroy() {
		System.out.println("Dependency destroy()");
	}
	public Resources getResources() {
		return resources;
	}
	public void setResources(Resources resources) {
		this.resources = resources;
	}
}

 配置

<bean id="resources" class="ioc.Resources" init-method="init" destroy-method="destroy"></bean>
	<bean id="dependency" class="ioc.Dependency" init-method="init" destroy-method="destroy" depends-on="resources">
		<property name="resources" ref="resources"></property>
	</bean>

 测试时使用ClassPathXmlApplicationContext获得IoC容器,因为只有容器个关闭才能看到调用destroy()

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Dependency dependency = context.getBean("dependency",Dependency.class);
context.close();
/**output:
Resources Constructor()
Resources init()
Dependency Constructor() 
Dependency init()
Dependency destroy()
Resources destroy()
*/ 

 案例七:单例bean

方式一:单例bean构造私有化

public class Singletion {

	private Singletion() {
	}

	public static class SingletionHandler {
		public static final Singletion INSTANCE = new Singletion();
	}

	public static Singletion getInstance() {
		return SingletionHandler.INSTANCE;
	}
}

方式二:将单例的bean通过唯一键注册到注册表,然后通过键值来获取,通过实现SingletonBeanRegistry接口来实现,不考虑多线程问题,Spring采用这种方式实现singleton

public class SingleonBeanRegister implements SingletonBeanRegistry {

	private final Map<String, Object> BEANS = new HashMap<String, Object>();

	public void registerSingleton(String beanName, Object singletonObject) {
		if (BEANS.containsKey(beanName)) {
			throw new RuntimeException("[" + beanName + "] already exist");
		}
		BEANS.put(beanName, singletonObject);
	}

	public Object getSingleton(String beanName) {
		return BEANS.get(beanName);
	}

	public boolean containsSingleton(String beanName) {
		return BEANS.containsKey(beanName);
	}

	public String[] getSingletonNames() {
		return BEANS.keySet().toArray(new String[0]);
	}

	public int getSingletonCount() {
		return BEANS.size();
	}

}

Spring配置方式,通过SpringIoC容器获得单例bean

定义bean

public class ScopeBean {}

 配置,不配置scope时默认就是singleton

<bean id="singleton" class="bean.ScopeBean" scope="singleton"></bean>

 测试

ScopeBean singleton1 =  context.getBean("singleton",ScopeBean.class);
		ScopeBean singleton2 =  context.getBean("singleton",ScopeBean.class);
		ScopeBean singleton3 =  context.getBean("singleton",ScopeBean.class);
		System.out.println(singleton1);
		System.out.println(singleton2);
		System.out.println(singleton3);
/**
bean.ScopeBean@30db7df3
bean.ScopeBean@30db7df3
bean.ScopeBean@30db7df3
*/

 案例八:prototype bean

模拟Spring实现,定义个bean

public class BeanDefinition {
	// 单例
	public static final int SCOPE_SINGLETON = 0;
	// 原型
	public static final int SCOPE_PROTOTYPE = 1;
	// 唯一标识
	private String id;
	// class全限定名
	private String clazz;
	// 作用域
	private int scope = SCOPE_SINGLETON;
}

 这侧表类

public class BeanDifinitionRegister {
	private final Map<String, BeanDefinition> DEFINITIONS = new HashMap<String, BeanDefinition>();

	public void registerBeanDefinition(String beanName, BeanDefinition bd) {
		if (DEFINITIONS.containsKey(bd.getId())) {
			throw new RuntimeException("[" + beanName + "] already exist");
		}
		DEFINITIONS.put(bd.getId(), bd);
	}

	public BeanDefinition getBeanDefinition(String beanName) {
		return DEFINITIONS.get(beanName);
	}

	public boolean containsBeanDefinition(String beanName) {
		return DEFINITIONS.containsKey(beanName);
	}
}

 定义工厂类用于获取bean实例

public class DefaultBeanFactory {
	// Bean定义注册表
	private BeanDifinitionRegister DEFINITIONS = new BeanDifinitionRegister();
	// 单例注册表
	private final SingletonBeanRegistry SINGLETONS = new SingletonBeanRegister();

	public Object getBean(String beanName) {
		// 1.验证Bean定义是否存在
		if (!DEFINITIONS.containsBeanDefinition(beanName)) {
			throw new RuntimeException("[" + beanName + "] already exist");
		}
		// 2.获取Bean定义
		BeanDefinition bd = DEFINITIONS.getBeanDefinition(beanName);
		// 3.是否该Bean定义是单例作用域
		if (bd.getScope() == BeanDefinition.SCOPE_SINGLETON) {
			// 3.1 如果单例注册表包含Bean,则直接返回该Bean
			if (SINGLETONS.containsSingleton(beanName)) {
				return SINGLETONS.getSingleton(beanName);
			}
			// 3.2单例注册表不包含该Bean, 则创建并注册到单例注册表,从而缓存
			SINGLETONS.registerSingleton(beanName, createBean(bd));
			return SINGLETONS.getSingleton(beanName);
		}
		// 4.如果是原型Bean定义,则直接返回根据Bean定义创建的新Bean,每次都是新的,无缓存
		if (bd.getScope() == BeanDefinition.SCOPE_PROTOTYPE) {
			return createBean(bd);
		}
		// 5.其他情况错误的Bean定义
		throw new RuntimeException("错误的Bean定义");
	}

	public void registerBeanDefinition(BeanDefinition bd) {
		DEFINITIONS.registerBeanDefinition(bd.getId(), bd);
	}

	private Object createBean(BeanDefinition bd) {
		// 根据Bean定义创建Bean
		try {
			Class clazz = Class.forName(bd.getClazz());
			// 通过反射使用无参数构造器创建Bean
			return clazz.getConstructor().newInstance();
		} catch (ClassNotFoundException e) {
			throw new RuntimeException("没有找到Bean[" + bd.getId() + "]类");
		} catch (Exception e) {
			throw new RuntimeException("创建Bean[" + bd.getId() + "]失败");
		}
	}
}

 测试

public class PrototypeTest {
	DefaultBeanFactory factory = null;

	@Before
	public void initContext() {
		factory = new DefaultBeanFactory();
	}

	@Test
	public void testPrototype() {
		BeanDefinition bd = new BeanDefinition();
		bd.setId("bean");
		bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
		bd.setClazz(BeanDefinition.class.getName());
		factory.registerBeanDefinition(bd);
		System.out.println(factory.getBean("bean"));
		System.out.println(factory.getBean("bean"));
		System.out.println(factory.getBean("bean"));
		System.out.println(factory.getBean("bean"));
	}
}

 Spring配置prototype

<bean id="singleton" class="bean.ScopeBean" scope="prototype"></bean>

 Spring中的bean的作用于出路Singleton和Prototype外还有三个与web有关的作用于分别为request(一起请求,比如一次表单提交)、session、global session,也可以通过实现Scope接口自己实现作用域范围

 

 

 

构造器注入:1、构造器参数索引 2、构造器参数类型 3、构造器参数类型

构造器注入通过<constructor-arg>标签配置,案例1、2、3使用第一种方式

 

SpringIoC容器依赖有两层含义:Bean初始化依赖于容器、容器注入Bean的依赖资源
 

二、DI

当一个对象的创建依赖于另外一个对象时,依赖就发生了,Spring的依赖是方法级的与对象中的属性无关

	class A {
		void setName(String name){
			// 就可以说 A 对象 依赖 String 类型参数
		}
		void setB(B b){
		    // 就可以说 A 对象 依赖 B 类型参数 
		}
	}

 实例bean,可以没有info属性,但必须有setXxxx()

public class InstanceBean {
	private String info;

	public InstanceBean() {
		System.out.println("...");
	}

	public void method() {
		System.out.println("InstanceBean--method()");
	}

	public String getInfo() {
		return this.info;
	}

	public void setInfo(String info) {
		this.info = info;
	}

}

 配置

<bean id="instance" class="demo01.InstanceBean">
		<property name="info" value="注入"></property>
	</bean>

 通过DI的方式为InstanceBean注入String类型对象

	@Test
	public void demo2(){
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		InstanceBean bean = (InstanceBean) applicationContext.getBean("instance");
		System.out.println(bean.getInfo());
	}

 这种对象间的依赖关系,通过Spring的使用配置文件的方式注入到InstanceBean中

 

三、Spring配置文件读取

一般有两个位置:

1、src根目录

2、WEB-INF下

最好命名为applicationContext.xml

读取方式

加载classpath:
	ew ClassPathXmlApplicationContext("applicationContext.xml");
加载磁盘路径:
	FileSystemXmlApplicationContext("WebContent/WEB-INF/applicationContext.xml");

 

 四、Spring实例化Bean的三种方式

1、使用构造器

实例化对象必须提供默认构造方法,配置如下

<bean id="instance" class="demo01.InstanceBean"></bean>

实例化

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
InstanceBean bean = applicationContext.getBean("instance",InstanceBean.class);

2、静态工厂方法

工厂类

public class BeanFactory {
	public static InstanceBean getInstanceBean() {
		return new InstanceBean();
	}
}

 配置

<bean id="instance1" class="demo01.BeanFactory" factory-method="getInstanceBean">
		<property name="info" value="静态工厂注入"></property>
	</bean>

实例化

	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		InstanceBean bean =  applicationContext.getBean("instance1",InstanceBean.class);

 3、实力工厂

工厂

public class BeanFactory {
	public  InstanceBean getInstanceBeen() {
		return new InstanceBean();
	}
}

配置

<bean id="beanFactory"  class="demo01.BeanFactory"></bean>
	<bean id="instance2"  factory-bean="beanFactory" factory-method="getInstanceBeen">
		<property name="info" value="实例工厂注入"></property>
	</bean>

 实例化

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		InstanceBean bean =  applicationContext.getBean("instance2",InstanceBean.class);
		System.out.println(bean.getInfo());

 

 五、Spring中Bean的作用域

Spring加载配置文件时,会默认为文件中所配置的所有bean实例化,实例化后,默认bean的实例为单利模式

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		InstanceBean bean1 =  applicationContext.getBean("instance",InstanceBean.class);
		InstanceBean bean2 =  applicationContext.getBean("instance",InstanceBean.class);
		System.out.println(bean1);
		System.out.println(bean2);

 还有其他几种类型

 

 

 

  • 大小: 83.8 KB
  • 大小: 13.7 KB
  • 大小: 6 KB
分享到:
评论

相关推荐

    spring in action 第二版 part1-part3

    Part1:Spring基础与核心概念 这部分首先介绍了Spring框架的基本理念和架构,包括依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)。读者将学习如何通过XML配置或Java配置...

    精通spring(part 4)共分5个part (罗时飞)

    - **非侵入式设计**:Spring采用依赖注入(Dependency Injection, DI)和面向接口编程,使得代码更加松耦合。 - **支持AOP**:Spring提供了强大的面向切面编程支持,可以轻松地实现事务管理等功能。 - **丰富的模块化*...

    ssm-spring-part.rar

    - **依赖注入(Dependency Injection, DI)**:这是IoC的一个方面,Spring通过DI管理对象间的依赖关系,避免了硬编码依赖,增强了组件的可测试性和可重用性。 - **面向切面编程(Aspect-Oriented Programming, AOP)...

    精通spring(part 1)共分5个part (罗时飞)

    - **IoC容器**:IoC容器是Spring的核心部分,负责管理对象的生命周期和配置。通过XML或注解的方式定义Bean,Spring IoC容器能够自动创建并注入所需的依赖。 - **AOP实现**:Spring AOP提供了强大的AOP支持,可以通过...

    SpringInAction2-part1-pic

    该压缩包文件“SpringInAction2-part1-pic”是《Spring in Action》第二版第一部分的配套图片资源,它旨在通过视觉方式帮助读者更好地理解书中所讲解的Spring框架的核心概念和技术。这本书是Spring框架的经典教程,...

    Spring 3.x企业应用开发实战光盘源码part02

    2. **IoC容器**:Spring的IoC容器负责创建对象、管理它们的生命周期和装配这些对象。它可以读取配置元数据(如XML或Java注解),根据这些信息创建和组装对象。 3. **AOP**:Spring的AOP支持使开发者能以声明的方式...

    spring 3 依赖包_part3

    Spring 3 依赖包是Java开发中至关重要的组成部分,它为开发者提供了丰富的功能,支持了面向切面编程(AOP)、依赖注入(DI)以及IoC容器等核心特性。在这个"spring 3 依赖包_part3"中,包含了多个第三方库,这些库在...

    struts1+spring+hibernate part2

    在Struts1中,Spring可以用来管理Action对象,通过Spring的IoC容器进行依赖注入,使得Action类的实例化和依赖关系的建立更加灵活。此外,Spring还提供了事务管理、数据访问抽象(如JdbcTemplate、HibernateTemplate...

    spring高级程序设计code

    这个压缩包文件包含了多个部分,从21204.part1.rar到21204.part6.rar,很可能是为了便于大文件传输而分割的。本文将详细解析Spring框架的核心概念和技术,以便更好地理解和应用Spring进行高级程序设计。 Spring是一...

    开发者突击:Java Web主流框架整合开发(part03和part04)(共6个压缩包)

    学习者将掌握Spring的IoC容器、Bean管理、AOP概念以及使用Spring MVC进行控制器、模型、视图和数据绑定。 3. **数据持久化框架Hibernate**:Hibernate是ORM(对象关系映射)框架,使得开发者可以使用Java对象直接...

    Spring.net中文说明

    1. 容器:Spring.NET的基石是IoC(Inversion of Control,控制反转)容器,它负责管理对象的生命周期,包括创建、配置、组装和管理对象。容器通过XML配置文件或代码方式来定义对象及其依赖关系。 2. AOP(面向切面...

    整合struts+hibernate+spring应用开发详解 part3

    4. **IoC(控制反转)与DI(依赖注入)**:这部分可能会深入解释Spring如何通过XML配置或注解实现对象的创建和依赖关系的管理,提高代码的灵活性和可扩展性。 5. **Struts2的核心概念**:如Action、Result、...

    精通spring2.x企业应用开发详解

    3. **IoC容器**:Spring的IoC容器是管理对象生命周期和依赖关系的中心,它负责创建对象、装配它们并管理其生命周期。 4. **数据访问集成**:Spring提供了对各种数据访问技术的支持,包括JDBC、Hibernate、JPA等,...

    整合struts+hibernate+spring应用开发详解 part1

    Spring的IoC容器负责管理对象的生命周期和依赖关系,使得代码更加松耦合。Spring还提供了与Hibernate的集成,可以方便地将两者结合在一起使用,减少了手动配置和数据访问的复杂性。 在这个教程的第二章,可能涵盖了...

    精通spring(part 5)共分5个part (罗时飞)

    - **BeanFactory**:是最基本的Spring IoC容器,它负责创建和管理Spring中的Bean。 - **ApplicationContext**:扩展了BeanFactory的功能,提供了更多的服务,比如资源访问、事件发布机制等。 #### 2.2 Bean的生命...

    Spring高级篇.pdf

    3. Web模块:包含Spring Web模块,它提供基础的面向web功能,包括多部分(multi-part)文件上传功能和使用Servlet监听器初始化IoC容器。还有Spring Web MVC模块,提供了模型-视图-控制器(MVC)框架。 4. AOP(面向...

    深入学习Spring

    通过阅读《精通Spring(清晰书签版)》.part1.rar和.part2.rar这两个压缩包文件,你将能系统地学习和掌握Spring框架的各个方面,提升自己的Java EE开发能力。这本书的内容详实,实例丰富,是Spring学习者不可多得的...

    Spring 入门大全和详细配置andAOP详解

    Spring入门-cl.part1.rar可能包含这些基础内容的视频教程。 3. **Spring配置** Spring配置主要分为XML配置和注解配置。XML配置是早期Spring的主要配置方式,通过`&lt;bean&gt;`标签定义对象并设置属性。随着版本的发展,...

    Spring in Action(第二版)中文版 (全)

    书中首先从Spring的基本架构入手,讲解了IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入)的概念,这是理解Spring的关键。IoC使得应用程序的组件之间解耦,而DI则通过容器管理对象之间...

    J2EE教程: Struts+Spring+JSF+Hibermate+EJB+XML+WebService+Ajax(part3)

    Spring的IoC容器使得对象的创建和管理更加简单,而其AOP模块则可以方便地实现横切关注点,如日志记录和事务管理。 3. **JavaServer Faces (JSF)**: JSF是J2EE标准的一部分,用于构建用户界面。它采用组件化的方式...

Global site tag (gtag.js) - Google Analytics