思想
Spring框架的思路是将应用程序中的不同部分进行解耦,使得应用程序的开发、测试、部署和维护变得更加简单、灵活和高效。Spring框架的是基于IOC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)的思想来实现的
IOC(控制反转)
传统的程序设计,我们需要手动创建对象、管理对象之间的关系和对象的生命周期。而在Spring框架中,控制权被反转,Spring容器负责管理对象之间的关系和对象的生命周期,我们只需要告诉Spring容器需要什么对象,Spring容器就会自动创建并管理这些对象。这种方式可以减少代码的耦合度,提高代码的可维护性和可重用性。
手动创建对象
下面是一个简单的 Java 代码示例,展示了如何手动创建和管理对象及其关系
public class Person {
private String name;
private int age;
private List<Person> children;
public Person(String name, int age) {
= name;
this.age = age;
this.children = new ArrayList<>();
}
public void addChild(Person child) {
this.children.add(child);
}
public static void main(String[] args) {
// 创建两个 Person 实例
Person father = new Person("John", 40);
Person son = new Person("Tom", 10);
// 建立父子关系
father.addChild(son);
}
}
在这个示例中,我们手动创建了两个 Person 对象,分别代表父亲和儿子。然后,我们调用 addChild 方法将儿子对象添加到父亲对象的 children 属性中,建立了父子关系。在这个过程中,我们需要手动管理对象之间的关系和对象的生命周期,以确保它们的正确性和一致性。
缺点:
- 复杂度高:手动创建和管理对象关系需要大量的代码和逻辑,这会增加代码的复杂度和维护成本。
- 容易出错:手动创建和管理对象关系容易出现错误,例如遗漏某些对象之间的关系、重复创建对象等等,这些错误可能会导致程序崩溃或产生错误的结果。
- 不易扩展:手动创建和管理对象关系不易扩展,例如添加新的对象类型或建立更复杂的关系需要更多的代码和逻辑。
- 难以维护:手动创建和管理对象关系可能会导致代码变得难以维护,特别是当对象关系变得复杂时,这会使代码更难以理解和调试。
- 不利于代码复用:手动创建和管理对象关系不利于代码的复用,因为代码通常是与特定的对象和关系相关联的,而不是通用的。这会导致代码冗余和维护成本的增加。
Spring创建对象
Spring 容器通过 IOC 容器负责管理对象之间的关系和对象的生命周期,主要是通过依赖注入(Dependency Injection)和生命周期回调(Lifecycle Callback)两个机制来实现的。
依赖注入是一种通过将对象依赖关系的创建和管理工作转移到框架来减少手动代码量和提高代码可维护性的技术。
生命周期回调是指容器在对象创建和销毁的不同阶段,自动调用对象中相应的回调方法。这样,我们就可以在对象的生命周期不同阶段做一些必要的操作,例如在对象创建时执行初始化方法,在对象销毁时执行清理方法等。
下面是一个简单的示例代码,展示 Spring 容器如何通过依赖注入和生命周期回调来管理对象之间的关系和对象的生命周期:
public class UserServiceImpl implements UserService, InitializingBean, DisposableBean {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("UserService afterPropertiesSet is called.");
}
@Override
public void destroy() throws Exception {
System.out.println("UserService destroy is called.");
}
@Override
public void addUser(User user) {
userDao.addUser(user);
}
}
public class UserDaoImpl implements UserDao {
@Override
public void addUser(User user) {
System.out.println("UserDao addUser is called.");
}
}
上面的代码中,UserService 和 UserDao 两个类之间存在依赖关系,UserService 需要依赖 UserDao 来实现具体的 addUser 方法。在 UserServiceImpl 类中,我们使用了依赖注入的方式,将 UserDao 对象注入进来。在 UserServiceImpl 类中,还实现了 InitializingBean 和 DisposableBean 接口,用来定义对象的初始化和销毁方法。在 afterPropertiesSet 方法中,我们可以做一些初始化操作,例如连接数据库等;在 destroy 方法中,我们可以做一些清理工作,例如关闭数据库连接等。
在 Spring 容器中,我们需要配置 UserServiceImpl 和 UserDao 的 Bean 定义,并定义它们之间的依赖关系。可以使用 XML 配置文件或 Java 注解的方式来实现。这里以 XML 配置文件的方式为例:
<bean id="userDao" class="com.example.UserDaoImpl" />
<bean id="userService" class="com.example.UserServiceImpl">
<property name="userDao" ref="userDao" />
</bean>
在这个配置中,我们先定义了 UserDaoImpl 的 Bean 定义,然后定义了 UserServiceImpl 的 Bean 定义,并使用 property 标签来注入 UserDao 对象。在容器启动时,Spring 会自动创建 UserDaoImpl 和 UserServiceImpl 的对象,并将 UserDaoImpl 对象注入到 UserServiceImpl 对象中。在 UserServiceImpl 对象的创建和销毁的不同阶段,容器会自动调用相应的回调方法。
AOP(面向切面编程)
传统的程序设计,我们将不同的业务逻辑分散在各个方法中,难以维护和复用。而在Spring框架中,我们可以使用AOP的思想将不同的业务逻辑划分为不同的切面,实现横切关注点与业务逻辑的分离,使得代码更加简洁、可维护和可重用。
使用场景
- 日志记录:记录方法的调用和执行时间、方法的参数和返回值等信息,可以帮助调试和分析程序性能。
- 事务管理:对于需要事务支持的方法,可以使用AOP来实现事务的开启、提交和回滚等操作,保证数据的一致性和完整性。
- 安全检查:对于需要进行权限检查的方法,可以使用AOP来实现安全控制,确保只有具有相应权限的用户才能访问受保护的资源。
下面是一个简单的示例代码,演示如何使用AOP来实现日志记录:
@Service
public class UserService {
public void addUser(User user) {
// ...
}
public User getUserById(int id) {
// ...
}
}
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Pointcut("execution(* com.example.UserService.*(..))")
public void serviceMethods() {}
@Around("serviceMethods()")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long elapsedTime = System.currentTimeMillis() - start;
("{} took {}ms", joinPoint.getSignature().toShortString(), elapsedTime);
return result;
}
}
在上面的示例中,UserService是一个业务服务类,其中包含了两个方法:addUser和getUserById。LoggingAspect是一个AOP切面类,使用@Aspect注解来标记,其中定义了一个切点serviceMethods,它匹配了UserService中的所有方法。在logExecutionTime方法中,使用@Around注解来标记环绕通知,它会在serviceMethods切点匹配到的方法执行前后执行。在方法执行前记录开始时间,在方法执行后记录结束时间和执行耗时,并将这些信息输出到日志中。
当UserService中的方法被调用时,如果匹配到了serviceMethods切点,就会触发LoggingAspect中的logExecutionTime方法执行,从而实现了日志记录的功能。
Spring框架的主要组成部分
- Spring核心容器:提供了IOC容器和AOP容器的实现,负责管理应用程序中的对象及其之间的关系和生命周期。
- Spring MVC:基于MVC架构实现的Web框架,提供了Controller、View、Model等组件,支持RESTful风格的Web服务开发。
- Spring数据访问:提供了对JDBC、ORM框架和NoSQL数据存储的支持,包括JdbcTemplate、HibernateTemplate、Spring Data等组件。
- Spring集成:提供了与其他框架和技术的集成支持,包括Struts、Hibernate、MyBatis、Quartz、ActiveMQ等。
- Spring安全:提供了对Web应用程序安全的支持,包括基于角色的访问控制、安全认证、加密解密等组件。
Spring中常用的设计模式
单例模式(Singleton Pattern)
Spring容器默认管理的Bean都是单例的,也就是在整个应用程序中只会创建一个实例。
在 Spring 中,我们可以使用 @Component 或者其衍生注解(如 @Service、@Repository、@Controller 等)来标记一个类为 Spring 的单例组件,示例代码如下:
@Component // 标记该类为 Spring 组件
public class MySingleton {
// ...
}
这样,在 Spring 应用程序中,每次使用 MySingleton 类型的对象时,Spring 都会返回同一个实例。
如果你需要自定义单例对象的初始化或者销毁逻辑,可以使用 @PostConstruct 和 @PreDestroy 注解来定义初始化方法和销毁方法,示例代码如下:
@Component // 标记该类为 Spring 组件
public class MySingleton {
@PostConstruct
public void init() {
// 在对象初始化时执行的逻辑
}
@PreDestroy
public void destroy() {
// 在对象销毁时执行的逻辑
}
}
使用 @PostConstruct 和 @PreDestroy 注解可以方便地管理单例对象的生命周期。
工厂模式(Factory Pattern)
Spring使用工厂模式来管理对象的创建,将对象的创建过程集中在一个工厂类中,实现了对象创建和业务逻辑的解耦。其中 Spring 提供了许多实现工厂模式的接口,如 FactoryBean 和 ObjectFactory
FactoryBean 接口实现工厂模式
@Component // 标记该类为 Spring 组件
public class MyFactoryBean implements FactoryBean<MyObject> {
@Override
public MyObject getObject() throws Exception {
// 创建 MyObject 对象的逻辑
MyObject myObject = new MyObject();
// ...
return myObject;
}
@Override
public Class<?> getObjectType() {
return MyObject.class;
}
}
上面的代码中,我们创建了一个实现 FactoryBean 接口的类 MyFactoryBean,并在 getObject() 方法中实现了创建 MyObject 对象的逻辑。getObjectType() 方法则返回了工厂所生产的对象类型。
我们还可以使用 @Configuration 和 @Bean 注解来创建一个对象工厂:
@Configuration
public class MyConfig {
@Bean
public ObjectFactory<MyObject> myObjectFactory() {
return MyObject::new; // 返回一个 lambda 表达式,用于创建 MyObject 对象
}
}
在上面的代码中,我们使用 @Bean 注解创建了一个返回 ObjectFactory 类型的方法,并在方法中返回一个 lambda 表达式,用于创建 MyObject 对象。
以上是 Spring 中使用工厂模式的两种示例,其中 FactoryBean 更加灵活,可以实现更加复杂的工厂逻辑,而 @Bean 注解则更加简单方便,适用于简单的工厂逻辑。
ObjectFactory接口实现工厂模式
@Component // 标记该类为 Spring 组件
public class MyObjectFactory implements ObjectFactory<MyBean> {
@Override
public MyBean getObject() {
// 返回一个新的 MyBean 实例
return new MyBean();
}
}
在上面的示例中,我们定义了一个实现了 ObjectFactory 接口的 MyObjectFactory 类,该类可以创建一个新的 MyBean 实例。在需要使用 MyBean 实例的地方,我们可以使用 ObjectFactory 来获取一个新的实例,示例代码如下:
@Component // 标记该类为 Spring 组件
public class MyService {
@Autowired
private ObjectFactory<MyBean> myBeanFactory;
public void doSomething() {
// 获取一个新的 MyBean 实例
MyBean myBean = myBeanFactory.getObject();
// 使用 MyBean 实例执行逻辑
}
}
在上面的示例中,我们将 MyObjectFactory 实例注入到了 MyService 类中,并在需要使用 MyBean 实例的地方使用 ObjectFactory 来获取一个新的实例。这种方式可以在需要时动态创建对象,并且可以通过依赖注入来管理对象的生命周期。
代理模式(Proxy Pattern)
Spring使用代理模式来实现AOP(面向切面编程),将横切关注点与业务逻辑分离,使得代码更加简洁、可维护和可重用。分别是基于JDK动态代理和基于CGLIB字节码生成的动态代理。
基于JDK动态代理
基于JDK动态代理的实现方式是,在运行时通过反射机制动态创建一个代理对象,该代理对象与目标对象实现相同的接口,并将方法的调用转发给目标对象。
下面是一个使用JDK动态代理实现AOP的示例代码:
public interface UserService {
void addUser(String username, String password);
}
public class UserServiceImpl implements UserService {
public void addUser(String username, String password) {
System.out.println("添加用户:username=" + username + ", password=" + password);
}
}
public class LogAspect {
public void before() {
System.out.println("记录日志:方法执行前");
}
public void after() {
System.out.println("记录日志:方法执行后");
}
}
public class UserServiceProxy implements InvocationHandler {
private UserService target;
private LogAspect logAspect;
public UserServiceProxy(UserService target, LogAspect logAspect) {
this.target = target;
this.logAspect = logAspect;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
logAspect.before();
Object result = method.invoke(target, args);
logAspect.after();
return result;
}
}
public class Main {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
LogAspect logAspect = new LogAspect();
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new UserServiceProxy(target, logAspect)
);
proxy.addUser("Alice", "123456");
}
}
在这个示例中,我们首先创建了一个UserService接口和一个实现了该接口的类UserServiceImpl,UserService接口定义了添加用户的方法addUser。然后创建了一个LogAspect类,其中包含了要织入目标对象的公共行为——记录日志。接下来创建了一个UserServiceProxy类,该类实现了InvocationHandler接口,并在invoke方法中将目标对象的方法调用转发给目标对象,并在调用前后分别调用记录日志的方法。最后,在Main方法中使用Proxy类的newProxyInstance方法动态创建代理对象,并调用代理对象的addUser方法,从而实现了AOP。
基于CGLIB字节码生成的动态代理
基于CGLIB字节码生成的实现方式是,在运行时使用字节码生成库创建一个代理类,并将代理类继承目标对象,从而实现对目标对象方法的拦截和增强。步骤如下:
- 创建目标对象,即要被代理的对象。
- 创建切面对象,即包含了要织入目标对象的公共行为的对象。
- 实现MethodInterceptor接口,该接口中定义了代理对象要执行的方法,其中代理对象的方法调用会被转发给目标对象。
- 使用Enhancer类的create方法创建代理对象。
public class UserService {
public void addUser(String username, String password) {
System.out.println("添加用户:username=" + username + ", password=" + password);
}
}
public class LogAspect implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("记录日志:方法执行前");
Object result = proxy.invokeSuper(obj, args);
System.out.println("记录日志:方法执行后");
return result;
}
}
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new LogAspect());
UserService proxy = (UserService) enhancer.create();
proxy.addUser("Alice", "123456");
}
}
在这个示例中,我们首先创建了一个UserService类,其中包含了添加用户的方法addUser。然后创建了一个LogAspect类,其中包含了要织入目标对象的公共行为——记录日志。接下来,在Main方法中使用Enhancer类的create方法创建代理对象,并将UserService类设置为父类,将LogAspect类设置为回调对象。最后,调用代理对象的addUser方法,从而实现了AOP。
AOP默认使用的动态代理模式
在Spring框架中,默认使用基于JDK动态代理的AOP实现。这是因为基于JDK动态代理的AOP实现可以针对接口进行代理,同时也具有良好的性能和稳定性。当然,如果目标对象没有实现任何接口,Spring会自动选择使用基于CGLIB字节码生成的动态代理。这时,Spring会在运行时通过生成目标对象的子类来实现代理,并重写目标对象的方法。需要注意的是,基于CGLIB字节码生成的动态代理实现不支持final方法和final类的代理。因此,在使用AOP时,如果目标对象是一个接口,则默认使用基于JDK动态代理的AOP实现;如果目标对象没有实现任何接口,则会使用基于CGLIB字节码生成的动态代理实现。
Spring框架中使用代理模式来实现AOP,可以在目标对象的方法执行前、执行后或者异常时,动态地织入一些公共的行为,比如日志记录、性能监控、事务管理等,从而使得业务逻辑与公共行为分离,提高了代码的可维护性和可重用性。
观察者模式
Spring事件驱动机制就是基于观察者模式实现的,当事件发生时,通知所有注册的监听器进行处理。
在Spring中,事件是通过ApplicationEvent类及其子类来表示的,而观察者则是通过实现ApplicationListener接口来完成的。
下面是一个简单的示例,演示如何在Spring中使用观察者模式来监听一个事件的发生:
首先,定义一个自定义事件类MyEvent:
public class MyEvent extends ApplicationEvent {
private String message;
public MyEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
接着,定义一个事件监听器MyEventListener,该监听器会在接收到MyEvent事件时输出事件的消息:
@Component
public class MyEventListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
System.out.println("Received message: " + event.getMessage());
}
}
最后,在代码的其他地方,需要使用ApplicationContext来发布事件:
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
ApplicationContext context = new AnnotationConfigApplicationContext(MyEventListener.class);
context.publishEvent(new MyEvent(new Object(), "Hello, world!"));
}
}
运行这个程序,会输出以下内容:
Received message: Hello, world!
这个例子中,我们定义了一个MyEvent事件,并定义了一个MyEventListener监听器。当使用ApplicationContext发布一个MyEvent事件时,监听器会自动接收到该事件并进行处理。这样,我们就利用观察者模式来实现了事件驱动编程。
模板方法模式(Template Method Pattern)
在Spring的JdbcTemplate中,JdbcTemplate类定义了执行JDBC操作的算法骨架,而具体的JDBC操作则由其子类实现。具体来说,JdbcTemplate使用了以下两个方法来实现模板方法模式:
- doInPreparedStatement:该方法是执行SQL语句的核心方法,它接收一个PreparedStatementCallback对象作为参数,并在其中执行SQL语句,并将结果传递给回调对象处理。在该方法中,JdbcTemplate提供了PreparedStatement对象和Connection对象等上下文信息,以便子类在执行SQL语句时使用。
- execute:该方法是JdbcTemplate中最常用的方法之一,它接收一个PreparedStatementCreator对象和一个PreparedStatementCallback对象作为参数,并在其中执行SQL语句。在该方法中,JdbcTemplate首先调用PreparedStatementCreator对象创建PreparedStatement对象,然后再将其传递给doInPreparedStatement方法执行。
通过使用模板方法模式,JdbcTemplate将执行JDBC操作的流程控制和具体的JDBC操作实现进行了解耦,使得JdbcTemplate能够更加灵活地处理各种JDBC操作。此外,JdbcTemplate还提供了一些方便的方法来支持命名参数、批量操作、存储过程等特定的JDBC操作。
适配器模式(Adapter Pattern)
在Spring MVC中,HandlerAdapter是用来适配Controller处理方法的接口,它提供了一种通用的方法来调用不同类型的Controller方法,使得Spring MVC可以支持多种不同类型的Controller方法。
HandlerAdapter采用了适配器模式的思想,它将不同类型的Controller方法适配成一个通用的接口,这样就可以使用同样的方式来处理所有不同类型的Controller方法。下面是一个简单的示例代码,演示了如何使用适配器模式来实现HandlerAdapter。
首先,我们定义一个Controller接口,它包含了一个handleRequest方法:
public interface Controller {
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
然后,我们实现两个不同类型的Controller方法:
public class SimpleController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("simple");
mav.addObject("message", "Hello World!");
return mav;
}
}
public class AnnotationController {
@RequestMapping("/hello")
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("annotation");
mav.addObject("message", "Hello World!");
return mav;
}
}
接下来,我们定义一个HandlerAdapter接口,它定义了一个可以适配不同类型Controller方法的handle方法:
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
最后,我们实现两个不同类型的HandlerAdapter适配器,一个用于适配SimpleController,一个用于适配AnnotationController:
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return (handler instanceof SimpleController);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
SimpleController controller = (SimpleController) handler;
return controller.handleRequest(request, response);
}
}
public class AnnotationControllerHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return (handler instanceof AnnotationController);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
AnnotationController controller = (AnnotationController) handler;
return controller.handleRequest(request, response);
}
}
这样,我们就可以使用这些适配器来处理不同类型的Controller方法了。当Spring MVC接收到一个请求时,它会通过已注册的HandlerAdapter适配器来找到一个能够处理这个请求的适配器,然后调用这个适配器的handle方法来处理请求。如果没有找到能够处理这个请求的适配器,就会返回一个404错误。
策略模式(Strategy Pattern)
在Spring中,DispatcherServlet是Spring MVC的核心组件之一,它负责接收HTTP请求并将请求分发给不同的Controller进行处理。DispatcherServlet使用策略模式来实现请求的处理和分发,它将不同的请求处理策略封装成了一个个策略对象,并根据请求的不同特征来选择相应的策略对象进行处理。下面是一个简单的示例代码,演示了如何使用策略模式来实现DispatcherServlet。
首先,我们定义一个HandlerMapping接口,它用来匹配请求和对应的Handler(即Controller和处理方法):
public interface HandlerMapping {
Object getHandler(HttpServletRequest request) throws Exception;
}
然后,我们实现两个不同类型的HandlerMapping策略对象,一个基于URI匹配,一个基于注解匹配:
public class SimpleUrlHandlerMapping implements HandlerMapping {
private Map<String, Object> urlMap = new HashMap<String, Object>();
public void setUrlMap(Map<String, Object> urlMap) {
this.urlMap = urlMap;
}
public Object getHandler(HttpServletRequest request) throws Exception {
String uri = request.getRequestURI();
Object handler = urlMap.get(uri);
if (handler == null) {
throw new ServletException("No handler found for uri: " + uri);
}
return handler;
}
}
public class AnnotationMethodHandlerMapping implements HandlerMapping {
private Map<String, Object> handlerMap = new HashMap<String, Object>();
public void setHandlerMap(Map<String, Object> handlerMap) {
this.handlerMap = handlerMap;
}
public Object getHandler(HttpServletRequest request) throws Exception {
String uri = request.getRequestURI();
String methodName = uri.substring(uri.lastIndexOf("/") + 1);
Object handler = handlerMap.get(methodName);
if (handler == null) {
throw new ServletException("No handler found for uri: " + uri);
}
return handler;
}
}
接下来,我们定义一个HandlerAdapter接口,它用来适配不同类型的Controller处理方法:
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
然后,我们实现两个不同类型的HandlerAdapter策略对象,一个用于适配SimpleController,一个用于适配AnnotationController:
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return (handler instanceof SimpleController);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
SimpleController controller = (SimpleController) handler;
return controller.handleRequest(request, response);
}
}
public class AnnotationControllerHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return (handler instanceof AnnotationController);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
AnnotationController controller = (AnnotationController) handler;
return controller.handleRequest(request, response);
}
}
最后,我们实现DispatcherServlet类,它使用HandlerMapping和HandlerAdapter策略对象来处理请求:
public class DispatcherServlet extends HttpServlet {
private List<HandlerMapping> handlerMappings;
private List<HandlerAdapter> handlerAdapters;
public void init() throws ServletException {
// 初始化handlerMappings和handlerAdapters
handlerMappings = new ArrayList<HandlerMapping>();
handlerMappings.add(new SimpleUrlHandlerMapping());
handlerMappings.add(new AnnotationMethodHandlerMapping());
handlerAdapters = new ArrayList<HandlerAdapter>();
handlerAdapters.add(new SimpleControllerHandlerAdapter());
handlerAdapters.add(new AnnotationControllerHandlerAdapter());
}
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Object handler = getHandler(request);
if (handler == null) {
throw new ServletException("No handler found for request: " + request.getRequestURI());
}
HandlerAdapter handlerAdapter = getHandlerAdapter(handler);
if (handlerAdapter == null) {
throw new ServletException("No handler adapter found for handler: " + handler);
}
ModelAndView modelAndView = handlerAdapter.handle(request, response, handler);
render(modelAndView, request, response);
} catch (Exception e) {
throw new ServletException("Failed to process request", e);
}
}
private Object getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping handlerMapping : handlerMappings) {
Object handler = handlerMapping.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
private HandlerAdapter getHandlerAdapter(Object handler) {
for (HandlerAdapter handlerAdapter : handlerAdapters) {
if (handlerAdapter.supports(handler)) {
return handlerAdapter;
}
}
return null;
}
private void render(ModelAndView modelAndView, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 根据modelAndView的视图名称,选择合适的视图解析器来解析视图并渲染
String viewName = modelAndView.getViewName();
ViewResolver viewResolver = new InternalResourceViewResolver();
View view = viewResolver.resolveViewName(viewName);
view.render(modelAndView.getModel(), request, response);
}
}