Spring的春天,直接召唤系--Singleton的Application Context

本文探讨了在不同环境下使用Spring容器的方法,包括直接召唤和IoC整合策略,详细介绍了如何在Web环境、单例类和EJB中应用Spring,并提供了实践示例。

   作者:江南白衣    

    Spring再强大,也要面对降临的问题--因为Spring不是Weblogic、Tomcat般的顶层容器,Servlet和EJB对象不由它创建,所以它必须要降临到Weblogic、Tomcat所在的位面。
     初学者一般不用管那么多,照着Spring+hibernate+Struts之类的Sample就做了,但慢慢的,也许就要开始在jsp+javabean体系,土制框架,singleton类等环境下使用Spring了。
     《Professional Java Development with the Spring Framework》第3章有"Managing the Containe"一节讲这个问题。一般可以分为直接召唤系与IoC fashion两类。

     1.直接召唤系--Singleton的Application Context
      最简单的,就像在UnitTest里那样,直接构造Application Context:

ApplicationContext ctx  =   new  ClasspathXmlApplicationContext( " ApplicationContext.xml " );

    
      在Web环境里,会使用ContextLoader构造ApplicationContext后,压进Servlet Context。
      由ContextLoaderListener或ContextLoaderServlet,在Web应用启动时完成。
      然后在Jsp/Servelet中,可以通过Servlet Context取得ApplicationContext:
ApplicationContext context  =  WebApplicationContextUtils.getWebApplicationContext(application);

     
      但像singleton类或者EJB中,就没有Servlet Context可用了。
      如果全部像UnitTest那样直接构造,速度就会很不堪。自然的,就想到把ApplicationContext做成单例。 
      Spring提供了 ContextSingletonBeanFactoryLocator这样的物体。
      先搞一个beanRefFactory.xml,里面写上所有的applcationContext-*.xml文件名,并把Context命名为"default-context":
< beans >
  
< bean id = " default-context "    class = " org.springframework.context.support.ClassPathXmlApplicationContext " >
    
< constructor - arg >
      
< list >   < value > applicationContext.xml </ value > </ list >
    
</ constructor - arg >
  
</ bean >
</ beans >

  然后让loactor去找它,但代码有点长:
BeanFactoryReference bfr =   DefaultLocatorFactory.getInstance().useBeanFactory("default-context");
BeanFactory factory  =  bfr.getFactory();
MyService myService 
=  factory.getBean( " myService " );
bfr.release();
//  now use myService


    上面的代码实在是太灵活,太麻烦了。
     还不如自己实现一个简单的Singleton,扩展ContextLoaderListener类,在Web系统启动时压入Singleton。

    
新的ContextLoaderListener类重载如下,ContextUtil中包含一个静态的ApplicationContext变量:
     public   void  contextInitialized(ServletContextEvent event)
    {
        
super .contextInitialized(event);

        ServletContext context 
=  event.getServletContext();
        ApplicationContext ctx 
=  WebApplicationContextUtils.getRequiredWebApplicationContext(context);
        ContextUtil.setContext(ctx);
    }

   用家可直接取用:
 ApplicationContext context  =  ContextUtil.getContext();


2.IoC fashion
    如果所有地方都使用直接召唤系,那就反而是在打Rod的耳光了。因为他一直都反对代码与框架深耦合的。
    所以,更好的方法是写一些glue code、base class来完成Spring的降临,而不让应用代码察觉Spring Application Context的存在。
    不过,因为各个框架的结构不同,Rod也没办法讲出一个通用的整合方法,所以建议大家尽量学习已整合的各种框架,如Spring MVC、Struts的种种方式,写出自己的简单整合代码来。

    只有不确定的调用某些Singleton类,不适合过早ioc的情况,可以使用直接召唤系。

D:\Java\bin\java.exe "-javaagent:D:\idea\idea2022\idea2022\IntelliJ IDEA 2022.2.3\lib\idea_rt.jar=58515:D:\idea\idea2022\idea2022\IntelliJ IDEA 2022.2.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\idea\idea2022\workspace\spring_aop\target\classes;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\spring-context\5.3.29\spring-context-5.3.29.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\spring-aop\5.3.29\spring-aop-5.3.29.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\spring-beans\5.3.29\spring-beans-5.3.29.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\spring-core\5.3.29\spring-core-5.3.29.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\spring-jcl\5.3.29\spring-jcl-5.3.29.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\spring-expression\5.3.29\spring-expression-5.3.29.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\aspectj\aspectjweaver\1.9.7\aspectjweaver-1.9.7.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-starter-aop\3.0.0\spring-boot-starter-aop-3.0.0.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-starter\3.0.0\spring-boot-starter-3.0.0.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot\3.0.0\spring-boot-3.0.0.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-autoconfigure\3.0.0\spring-boot-autoconfigure-3.0.0.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-starter-logging\3.0.0\spring-boot-starter-logging-3.0.0.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\ch\qos\logback\logback-classic\1.4.5\logback-classic-1.4.5.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\ch\qos\logback\logback-core\1.4.5\logback-core-1.4.5.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\slf4j\slf4j-api\2.0.4\slf4j-api-2.0.4.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\apache\logging\log4j\log4j-to-slf4j\2.19.0\log4j-to-slf4j-2.19.0.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\apache\logging\log4j\log4j-api\2.19.0\log4j-api-2.19.0.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\slf4j\jul-to-slf4j\2.0.4\jul-to-slf4j-2.0.4.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;D:\BaiduNetdiskDownload\Maven 3.6.3\apache-maven-3.6.3\repository\org\yaml\snakeyaml\1.33\snakeyaml-1.33.jar" com.itheima.App 14:44:49.877 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7c30a502 14:44:49.889 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' 14:44:49.923 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [D:\idea\idea2022\workspace\spring_aop\target\classes\com\itheima\dao\Impl\UserDaoImpl.class] 14:44:49.979 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor' 14:44:49.981 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 14:44:49.982 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 14:44:49.984 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator' 14:44:50.043 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'springConfig' 14:44:50.047 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userDaoImpl' UserDao save 还是没打印
最新发布
09-26
Spring AOP项目中,'UserDao save'未打印可能由多种原因导致,以下是一些常见的解决办法: ### 检查AOP配置 确保AOP功能已正确启用。在Spring Boot项目中,只要添加了`spring-boot-starter-aop`依赖,AOP默认是启用的。确认`pom.xml`中包含该依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>3.0.0</version> </dependency> ``` ### 检查切面类配置 确保切面类的配置正确,包括切入点表达式和通知方法。以下是一个简单的切面类示例: ```java import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class UserDaoAspect { @After("execution(* com.example.dao.UserDao.save(..))") public void afterUserDaoSave(JoinPoint joinPoint) { System.out.println("UserDao save"); } } ``` 要注意切入点表达式`execution(* com.example.dao.UserDao.save(..))`,需确保其能正确匹配到`UserDao`类的`save`方法。 ### 检查目标类和方法 确保`UserDao`类和`save`方法存在,并且是Spring管理的Bean。例如: ```java import org.springframework.stereotype.Repository; @Repository public class UserDao { public void save() { // 保存操作 } } ``` ### 检查日志级别 确保日志级别不会过滤掉相关日志。在`application.properties`或`application.yml`中检查日志配置,例如: ```properties logging.level.root=INFO ``` ### 检查代理模式 Spring AOP默认使用基于接口的JDK动态代理,如果目标类没有实现接口,需要使用CGLIB代理。在Spring Boot中,默认会自动选择合适的代理模式,但可以通过配置强制使用CGLIB代理: ```properties spring.aop.proxy-target-class=true ``` ### 检查IDE配置 确保项目在IntelliJ IDEA中正确编译和运行,没有编译错误或依赖问题。可以尝试重新构建项目,清除缓存等操作。 ### 调试和日志输出 在切面方法和目标方法中添加更多的日志输出,以确认方法是否被调用。例如: ```java @Aspect @Component public class UserDaoAspect { @After("execution(* com.example.dao.UserDao.save(..))") public void afterUserDaoSave(JoinPoint joinPoint) { System.out.println("进入切面方法 afterUserDaoSave"); System.out.println("UserDao save"); } } @Repository public class UserDao { public void save() { System.out.println("进入UserDao save方法"); // 保存操作 } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值