Spring 的静态工厂方法

Spring的静态工厂方法 http://blog.csdn.net/chensugang/article/details/3357593 上一次写了一篇关于DI的三种方式,其中里面介绍了构造方法的方式,今天学习了一种替代构造器的方法,这就是静态工厂方法来返回对象,下面来看一下静态工厂方法的实现。 静态工厂方法: LoginAction类: package com.spring.test.di; public class LoginAction { private Logic logic; private LoginAction(Logic logic){ this.logic = logic; } public static LoginAction createInstance(Logic logic){ LoginAction loginAction = new LoginAction (logic); return loginAction; } public void execute() { String name = logic.getName(); System.out.print("My Name Is " + name); } } 注意: 这里使用的构造方法是一个私有方法,createInstance这个就是我们的静态工厂方法 Logic接口: package com.spring.test.di; public interface Logic { public String getName(); } 这里只是做为一个简单的例子,所以我们在该接口中只有一个方法,并且在该接口的实现方法也超级简单 ...

Created 26266-03-26 · Updated 9096-10-09 · 1 min · 170 words · -

Spring 中 bean 的作用域

Spring中bean的作用域 http://blog.csdn.net/ProvidenceZY/article/details/1878582 如何使用spring的作用域: <bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/> 这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。 在spring2.0之前bean只有2种作用域即: singleton(单例)、non-singleton (也称prototype) , Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类型,满足实际应用需求。 1、singleton作用域 当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存 (singleton cache) 中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。 配置实例: <bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/> 或者 <bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/> 2、prototype prototype作用域部署的bean,每一次请求 (将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法) 都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。 (让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。) 配置实例: <bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/> 或者 <beanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/> 3、request request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例: request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置: 如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可: <web-app> ... <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> ... </web-app> 如果是Servlet2.4以前的web容器,那么你要使用一个javax.servlet.Filter的实现: <web-app> .. <filter> <filter-name>requestContextFilter</filter-name> <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> </filter> <filter-mapping> <filter-name>requestContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ... </web-app> 接着既可以配置bean的作用域了: <bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/> 4、session session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效,配置实例: 配置实例: ...

Created 16166-09-16 · Updated 9096-10-09 · 2 min · 218 words · -

PropertyPlaceholderConfigurer

PropertyPlaceholderConfigurer http://callan.iteye.com/blog/161540 关于PropertyPlaceholderConfigurer与PropertyOverrideConfigurer PropertyPlaceholderConfigurer,允许在spring的配置文件中加入properties文件,可以将一些动态参数移到properties中. <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:config/jdoserver.properties"/> </bean> 但是好像在属性文件定义中却不支持多个属性文件的定义,比如不能这样用config/*.properties。 经过查看源码,发现可以使用locations属性定义多个配置文件: <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:config/maxid.properties</value> <value>classpath:config/jdoserver.properties</value> </list> </property> </bean> 使用外部属性后如下: <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.agent.driver}"/> <property name="url" value="${jdbc.agent.main.url}"/> </bean> PropertyOverrideConfigurer: 在spring所有的bean初使化以后,将bean的值强行改变 <bean id="configBean" class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"> <property name="location"> <value>hello.properties</value> </property> </bean> <bean id="helloBean" class="com.HelloBean"> <property name="word"> <value>Hello!</value> </property> </bean> 定义HelloBean,注入word的值为hello. 在hello.properties中 helloBean.word=Welcome! word初使为hello后,当bean全加载完,PropertyOverrideConfigurer将helloBean.word的值改成为welcome. 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 8086-12-08 · Updated 9096-10-09 · 1 min · 73 words · -

Spring Annotation @Resource

Spring Annotation @Resource Spring 不但支持自己定义的 @Autowired 的注释,还支持几个由 JSR-250 规范定义的注释,它们分别是@Resource、@PostConstruct 以及 @PreDestroy。 @Resource @Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,面 @Resource 默认按 byName 自动注入罢了。@Resource 有两个属性是比较重要的,分别是 name 和 type,Spring 将 @Resource 注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。 @Resource装配顺序 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常 如果指定了name,则从上下文中查找名称 (id) 匹配的bean进行装配,找不到则抛出异常 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配 (见2) ;如果没有匹配,则回退为一个原始类型 (UserDao) 进行匹配,如果匹配则自动装配; Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。 @Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。 @Resource装配顺序 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常 如果指定了name,则从上下文中查找名称 (id) 匹配的bean进行装配,找不到则抛出异常 ...

Created 16166-01-16 · Updated 9096-10-09 · 2 min · 358 words · -

利用 Spring 的 JdbcTemplate 处理 BLOB、CLOB

利用spring的jdbcTemplate处理blob、clob spring定义了一个以统一的方式操作各种数据库的Lob类型数据的LobCreator(保存的时候用),同时提供了一个LobHandler为操作二进制字段和大文本字段提供统一接口访问。 举例,例子里面的t_post表中post_text字段是CLOB类型,而post_attach是BLOG类型: public class PostJdbcDao extends JdbcDaoSupport implements PostDao { private LobHandler lobHandler; private DataFieldMaxValueIncrementer incre; public LobHandler getLobHandler() { return lobHandler; } public void setLobHandler(LobHandler lobHandler) { this.lobHandler = lobHandler; } public void addPost(final Post post) { String sql = " INSERT INTO t_post(post_id,user_id,post_text,post_attach)" + " VALUES(?,?,?,?)"; getJdbcTemplate().execute( sql, new AbstractLobCreatingPreparedStatementCallback( this.lobHandler) { protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException { ps.setInt(1, incre.nextIntValue()); ps.setInt(2, post.getUserId()); lobCreator.setClobAsString(ps, 3, post.getPostText()); lobCreator.setBlobAsBytes(ps, 4, post.getPostAttach()); } }); } } 设置相对应的配置文件(Oracle 9i版本),Oracle的数据库最喜欢搞搞特别的东西啦: ...

Created 16166-01-16 · Updated 9096-10-09 · 2 min · 219 words · -

Spring 生成 EntityManagerFactory 的三种方式

spring生成EntityManagerFactory的三种方式 1.LocalEntityManagerFactoryBean 只是简单环境中使用。它使用JPA PersistenceProvider自动检测机制( according to JPA’s Java SE bootstrapping ),并且大多数情况下,你只能定义一下persistence unit name 例如: <beans> <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="myPersistenceUnit"/> </bean> </beans> 2.从JNDI获取EntityManagerFactory 这个选项是当你应用发布在javaee5的服务器中。你可以参阅自己应用服务器文档,如何发布一个自定义的JPA provider到你的应用服务器中。 例: <beans> <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/> </beans> 当javaee服务器启动时,会自动检测persistence units。实际上,是检测应用包中的META-INF/persistence.xml 文件和web.xml中的persistence-unit-ref,以及定义的environment naming。我理解就是JNDI的name。 一般应用情景是: 在META-INF/persistence.xml中 使用<jta-data-source>java:/ MySQLDS</jta-data-source> 获取容器发布的Datesource。 transactions是使用的javaee容器支持的JTA系统,例如tomcat中,可以这样 如果你的项目准备部署在tomcat上,要支持jta,则需把相关的包放在tomcat/lib包下 jndi配置,可以把jndi的配置放置在 tomcat/conf/Catalina/域名(如localhost)/项目名.xml 文件的Context节点下,如下: <Resource name="" auth="Container" type="javax.sql.DataSource" username="" password="" driveClassName="oracle.jdbc.driver.OracleDriver" url="" maxActive="45" maxIdle="25"/> jndi也可以配置在server.xml,context.xml中 2)jta UserTransaction配置 在server.xml文件GlobalNamingResources节点下配置如下: <!- Resource configuration for UserTransaction use JOTM -> <Resource name="UserTransaction" auth="Container" type="javax.transaction.UserTransaction" factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60"/> 然后在 项目名.xml 文件的context节点下加: <ResourceLink name="UserTransaction" global="UserTransaction" type="javax.transaction.UserTransaction"/> SPRING 仅仅做的是是把EntityManagerFactory通过依赖注入到应用的object中。如果要管理事务,则使用JtaTransactionManager。 3.LocalContainerEntityManagerFactoryBean ...

Created 29296-05-29 · Updated 9096-10-09 · 2 min · 291 words · -

spring quartz

spring quartz http://www.oschina.net/question/8676_9032 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <ref bean="testTrigger"/> </list> </property> <property name="autoStartup" value="true"/> </bean> 说明: Scheduler包含一个Trigger列表,每个Trigger表示一个作业。 2、Trigger的配置 <bean id="testTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="testJobDetail"/> <property name="cronExpression" value="*/1 * * * * ?"/><!-- 每隔1秒钟触发一次 --> </bean> 说明: Cron表达式的格式: 秒 分 时 日 月 周 年(可选)。 字段名 允许的值 允许的特殊字符 秒 0-59 , - * / 分 0-59 , - * / 小时 0-23 , - * / 日 1-31 , - * ? / L W C 月 1-12 or JAN-DEC , - * / 周几 1-7 or SUN-SAT , - * ? / L C # ...

Created 7076-11-07 · Updated 9096-10-09 · 2 min · 242 words · -

spring @value

spring @value 在spring 3.0中,可以通过使用@value,对一些如xxx.properties文件 中的文件,进行键值对的注入,例子如下: 1 首先在applicationContext.xml中加入: <beans xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd"> </beans> 的命名空间,然后 <util:properties id="settings" location="WEB-INF/classes/META-INF/spring/test.properties" /> 3 创建test.properties abc=123 import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @RequestMapping("/admin/images") @Controller public class ImageAdminController { private String imageDir; @Value("#{settings[’test.abc’]}") public void setImageDir(String val) { this.imageDir = val; } } 这样就将test.abc的值注入了imageDir中了 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;categories 改为 Java 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 7076-11-07 · Updated 9096-10-09 · 1 min · 65 words · -

Spring 静态注入的三种方式

Spring静态注入的三种方式 Spring静态注入的三种方式: (说明: MongoFileOperationUtil是自己封装的一个Mongodb文件读写工具类,里面需要依赖AdvancedDatastore对象实例,dsForRW用来获取Mongodb数据源) 在springframework里,我们不能@Autowired一个静态变量,使之成为一个spring bean,例如下面这种方式: @Autowired private static AdvancedDatastore dsForRW; 可以试一下,dsForRW在这种状态下不能够被依赖注入,会抛出运行时异常java.lang.NullPointerException,为什么呢?静态变量/类变量不是对象的属性,而是一个类的属性,spring则是基于对象层面上的依赖注入。 但是自己比较喜欢封装工具类,并通过@Component注解成功能组件,但是功能组件中的方法一般都是静态方法,静态方法只能调用静态成员变量,于是就有了下面的问题。封有的时候封装功能组件会需要底层的service注入,怎么办呢? 去网上搜了下解决办法,简单总结一下几种实现方式; 1.xml方式实现; <bean id="mongoFileOperationUtil" class="com.\*.\*.MongoFileOperationUtil" init-method="init"> <property name="dsForRW" ref="dsForRW"/> </bean> public class MongoFileOperationUtil { private static AdvancedDatastore dsForRW; private static MongoFileOperationUtil mongoFileOperationUtil; public void init() { mongoFileOperationUtil = this; mongoFileOperationUtil.dsForRW = this.dsForRW; } } 这种方式适合基于XML配置的WEB项目; 2.@PostConstruct方式实现; import org.mongodb.morphia.AdvancedDatastore; import org.springframework.beans.factory.annotation.Autowired; @Component public class MongoFileOperationUtil { @Autowired private static AdvancedDatastore dsForRW; private static MongoFileOperationUtil mongoFileOperationUtil; @PostConstruct public void init() { mongoFileOperationUtil = this; mongoFileOperationUtil.dsForRW = this.dsForRW; } } @PostConstruct 注解的方法在加载类的构造函数之后执行,也就是在加载了构造函数之后,执行init方法;(@PreDestroy 注解定义容器销毁之前的所做的操作) ...

Created 6066-02-06 · Updated 9096-10-09 · 1 min · 153 words · -

Spring IoC,依赖注入

IoC(Inversion of Control,控制反转)是 Spring 的核心机制。它把"创建和管理对象"的控制权从应用代码交给 Spring 容器,应用代码只需声明依赖,容器负责提供。Spring Framework 整体定位见 Spring。 IoC 的具体实现方式叫 DI(Dependency Injection,依赖注入),容器通过构造器、字段或 Setter 方法将依赖对象注入进来。 IoC 解决了什么问题 传统写法中,对象自己负责创建依赖: // 传统写法:自己创建依赖,紧耦合 public class OrderService { private UserDao userDao = new UserDaoImpl(); // 自己 new,换实现要改代码 private EmailService email = new EmailService("smtp.example.com", 465); } 这带来三个问题: 紧耦合:OrderService 直接依赖具体实现类,换实现必须修改源码 难以测试:无法替换成 Mock 对象,单元测试困难 对象生命周期散乱:每次 new 都产生新对象,无法复用单例 IoC 写法: // IoC 写法:声明需要什么,容器负责提供(推荐构造器注入) @Service public class OrderService { private final UserDao userDao; private final EmailService emailService; public OrderService(UserDao userDao, EmailService emailService) { this.userDao = userDao; this.emailService = emailService; } } 切换实现时只需修改容器配置(或替换实现类上的 @Primary / @Qualifier),OrderService 代码本身不用动。 ...

Created 12126-05-12 · Updated 11116-08-11 · 9 min · 1753 words · -

Spring Boot Startup Callbacks: 应用启动后执行逻辑

若要在 Spring 应用上下文已就绪 之后执行一段初始化代码,常见做法如下。多个 Bean 可同时实现同一类接口,使用 @Order 或 Ordered 控制顺序。框架总览见 Spring Boot。 ApplicationRunner 与 CommandLineRunner 二者都会在 SpringApplication 启动流程末尾被调用。需要结构化解析命令行参数(如 key=value 形式)时,优先使用 ApplicationRunner(入参为 ApplicationArguments);只关心原始字符串数组时用 CommandLineRunner 即可。 @Component @Order(1) public class SeedDataRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) { // post-startup logic } } @Component @Order(2) public class BannerRunner implements CommandLineRunner { @Override public void run(String... args) { // post-startup logic } } @PostConstruct 在某个 Spring Bean 完成依赖注入之后、对外使用前执行,适合该 Bean 自身的轻量初始化。不要在 static 方法上使用 @PostConstruct(规范要求实例方法)。 ...

Created 26266-06-26 · Updated 11116-08-11 · 1 min · 135 words · wiloon

Spring Bean Lifecycle: 从实例化到销毁

Spring 容器管理的不只是"创建对象",还包括从实例化到销毁的完整过程。容器概览见 Spring IoC;本文聚焦单个 singleton Bean 从 new 到被销毁经历的各个阶段。 整体流程 graph TD A[实例化调用构造器] --> B[属性填充依赖注入] B --> C[Aware 接口回调] C --> D[BeanPostProcessor前置处理] D --> E["初始化回调PostConstruct → afterPropertiesSet → init-method"] E --> F[BeanPostProcessor后置处理AOP 代理在此生成] F --> G[就绪可用] G --> H[容器关闭] H --> I["销毁回调PreDestroy → destroy → destroy-method"] singleton Bean 只走一次这套完整流程;prototype Bean 只做到"就绪可用",容器交出对象后就不再管理,销毁阶段(H、I)不会发生——细节见 Spring 中 Bean 的作用域。 实例化与属性填充 容器先按 BeanDefinition 里记录的构造器(或工厂方法)创建原始对象,再做属性填充(即依赖注入,见 Spring IoC §依赖注入的三种方式)。这两步是循环依赖唯一可能出现的阶段——对象已存在但还没准备好被别人安全引用。 三级缓存与循环依赖 以 A 依赖 B、B 又依赖 A(字段注入或 Setter 注入场景)为例: sequenceDiagram participant C as Container participant A as Bean A participant B as Bean B C->>A: new A()(原始对象,属性未填) C->>C: A 的 ObjectFactory 放入三级缓存 C->>A: 注入属性,发现需要 B C->>B: new B()(原始对象) C->>C: B 的 ObjectFactory 放入三级缓存 C->>B: 注入属性,发现需要 A C->>C: 查 A:一级 miss,二级 miss,三级 hit C->>C: 调用 ObjectFactory 得到 A 的早期引用 C->>C: 早期引用移入二级缓存,移除三级缓存 C->>B: 注入 A 的早期引用,B 创建完成 C->>C: B 放入一级缓存 C->>A: 用完成态的 B 完成属性注入,A 创建完成 C->>C: A 放入一级缓存,清理二三级缓存里的临时数据 容器创建 A:new A() 已经创建出 A 的真实原始对象(构造器已执行完毕,只是属性还没注入)。Spring 把「如何暴露这个已存在的原始对象」包装成一个 ObjectFactory(本质是个 () -> getEarlyBeanReference(...) 的 lambda,调用它才会决定返回原始对象还是 AOP 代理),再把这个工厂本身放进三级缓存 singletonFactories,并把 A 标记为「正在创建中」。也就是说,三级缓存里存的是「怎么拿到早期引用」的工厂,不是对象本身;对象在 new 这一步就已经真实存在了。 给 A 注入属性时发现需要 B,转去创建 B,同理:new B() 创建出真实的原始对象,再把它的 ObjectFactory 放进三级缓存。 给 B 注入属性时发现需要 A:依次查一级(没有,A 还没做完)、二级(没有)、三级缓存——命中 A 的 ObjectFactory,调用它拿到 A 的早期引用,挪进二级缓存并从三级缓存移除。 B 用这个早期引用完成注入、创建完成,放入一级缓存。 流程回到 A:用刚创建好的 B 完成属性注入,A 也创建完成,放入一级缓存。 三级缓存各自存的到底是什么(一级、二级缓存的底层结构见 Spring IoC §单例缓存怎么存): ...

Created 11116-08-11 · Updated 11116-08-11 · 3 min · 597 words · -

Spring AOT

是什么 Spring AOT(Ahead-Of-Time)是 Spring Framework 6 / Spring Boot 3 引入的构建期处理机制:在打包或 Native 编译之前,对 Spring ApplicationContext 做静态分析,生成预先计算好的 bean 定义、反射/资源 hint,以及(可选)面向 GraalVM Native Image 的入口代码。 默认 Spring Boot 应用在运行时做 classpath 扫描、@Configuration 解析、条件装配(@Conditional / @ConditionalOn*)和大量反射;Spring AOT 把这些工作尽量前移到构建期,使: 在 HotSpot JVM 上跑的处理后 JAR,启动更快(仍用 java -jar) 在 GraalVM Native Image 路径上,构建器能拿到闭世界分析所需的元数据 不要和 JDK AOT 混淆 博客与 JDK 发行说明里还有另一类「AOT」,含义不同: 名称 层级 做什么 Spring AOT Spring 框架 / Boot 插件 构建期处理 IoC 容器,生成 bean 与 Native hint GraalVM Native Image AOT GraalVM 工具链 字节码 → 本地机器码 + Substrate VM JDK AOT 缓存(JEP 483 等) HotSpot JVM 训练运行后缓存类加载/链接/剖析,缩短下次 JVM 冷启动 Spring AOT 常与 GraalVM Native Image 配合使用,但不是同一 thing;JDK 24+ 的 AOT 缓存与 Spring AOT 可以并存,也互不替代。JDK 侧见 JDK 25 变更汇总、JVM 编译器。 ...

Created 21216-06-21 · Updated 15156-07-15 · 3 min · 596 words · -

2026 W27

女儿上幼儿园的情绪课 这周女儿在排练小班毕业表演,舞蹈动作有点难,加上分离焦虑,早上去幼儿园成了每天要过的一关。周一那天她抗拒得厉害,做了近一个小时心理建设才送进去,迟到了一小时。 我试着用她熟悉的东西帮她面对情绪。她在玩《星之卡比》,一开始连第一关的兔子都怕,现在已经把卡比的装备升到四级了。我就问她:现在还怕第一关的兔子吗?她说不怕了。我说幼儿园跳舞也一样,你手里的"冰淇淋"(舞蹈道具)现在是几级装备?她说是一级。我说今天带着它去跳舞,明天就升到二级,跳舞就没那么难了。她点点头,跟妈妈说了再见,蹦蹦跳跳去幼儿园"升级装备"了。 后面几天肉眼可见地在进步。周三到门口离开妈妈还会有点不开心,安抚一会儿就自己跑进去了。周四早上我在路上问她冰淇淋几级了,她说二级;我说今天再升一级,她纠正我:不对,上午能升一级,下午还能再升一级。大概她的神经网络已经把跳舞和打怪升级关联起来了。 比起替她扛下情绪,更想让她自己有面对情绪的办法。这套比喻能不能一直管用不好说,但这周是有效的。 周六全天带娃,出门时她的"小怪兽钱包"里有些现金。到星海广场,她自己花十块买了一袋海鸥食,又花三十坐了小火车,接着想玩旋转木马,翻钱包发现只剩十三块六了。她开始琢磨:游乐场都是收费三十吗?我说我们去找找十三块能玩哪个。绕了一圈,路过一个转飞船的场地,工作人员大姐答应十三块让她上去坐一圈。让她花自己的压岁钱,她就开始比较各种东西的价格了。 求职 周二收到了一家公司的面试邀请,周五去参加,过程还算顺利,有些问题答得还好,有些答得一般。目前结果未知。 咖啡:蒸气奶测试 某天中午送老婆去公司后,我又带电脑在她楼下的星巴克找了个座位。那天出门晚,担心喝咖啡影响睡眠,又不好久占座位,翻了半天菜单,看到一项叫"蒸气奶"。跟 AI 确认了一下,蒸气奶大致等于拿铁去掉咖啡。之前喝拿铁不会触发乳糖不耐,蒸气奶应该也安全。选项里有牛奶也有燕麦奶,我选了普通牛奶——顺便测试一下:蒸气乳化的过程据说能分解一部分乳糖,气泡也可能减缓乳糖进入肠道的速度。结果跟之前喝拿铁一样,喝完没有触发乳糖不耐的症状。

Created 5056-07-05 · Updated 8086-07-08 · 1 min · 12 words · -

Spring Security

SecurityFilterChain SecurityFilterChain 是 Spring Security 的核心抽象,代表一条作用于 HTTP 请求的安全过滤器链。每个进入应用的请求都会依次经过链中的若干 Filter,完成认证(Authentication)、授权(Authorization)、CSRF 防护、会话管理等工作。 底层机制:从 Servlet Filter 到 Spring Security Servlet 规范本身有 Filter 接口和 FilterChain 接口。Spring Security 通过以下两层代理接入这套机制: DelegatingFilterProxy:在 Servlet 容器(Tomcat)层面注册的 Filter,作用是把请求桥接到 Spring 容器中的 Bean。它本身不做安全逻辑,只是一个"入口代理"。 FilterChainProxy:Spring 容器中的真正实现,也是一个特殊的 Filter。它持有所有注册的 SecurityFilterChain Bean,收到请求后,按顺序匹配第一条能处理该 URL 的链,然后依次执行链中的每个 Filter。 HTTP 请求 → Tomcat FilterChain → DelegatingFilterProxy(Servlet Filter,桥接到 Spring,Bean 名固定为 springSecurityFilterChain) → FilterChainProxy(Spring Bean,收集所有 SecurityFilterChain) → SecurityFilterChain 1(匹配 /api/**) UsernamePasswordAuthenticationFilter BearerTokenAuthenticationFilter ExceptionTranslationFilter AuthorizationFilter ... → SecurityFilterChain 2(匹配 /**) ... ← 链中最后一个 Filter 放行(chain.doFilter()),控制权交回 DelegatingFilterProxy → Tomcat FilterChain 继续执行其余 Filter(如果有) → DispatcherServlet → HandlerMapping 找到目标 Controller 方法 → Controller SecurityFilterChain Bean 如何被收集并接入请求 在 @Configuration 类里写的 @Bean public SecurityFilterChain filterChain(...) 方法,只是往 IoC 容器里注册了一个数据对象——具体实现类是 DefaultSecurityFilterChain,内部就是一个 Filter 列表加一个 RequestMatcher。真正让这份数据接入请求处理流程,还需要另外两步: ...

Created 23236-12-23 · Updated 1016-07-01 · 4 min · 781 words · -

Spring 事务 @Transactional

spring 事务 @Transactional 使用 @Transactional 的要点有: 在DAO 层使用 JdbcTemplate 实现DB操作, 在 Service 的实现类上加上 @Transactional 注解, 不推荐在 Service 接口上加 @Transactional 注解. 需要进行事务控制的方法, 必须是 public 方法, 同时要打上 @Transactional 注解. 也可以在Class上加上 @Transactional 注解, 这样相当于给每个 public 函数加上了 @Transactional 注解, 当然我们还可以在其中的函数上加该注解, 这时候将以函数上的设置为准. @Transactional 失效场景 只有 public 方法生效:private/protected/包级方法上加 @Transactional 不生效,因为 Spring 默认约定只处理 public 方法(CGLIB 虽然能代理 protected 方法,但 Spring 事务模块不支持)。 同类自调用(self-invocation):@Transactional 依赖 Spring AOP 生成的代理对象,只有通过代理调用方法才会走事务逻辑。同一个类内部用 this.xxx() 直接调用会绕过代理,导致事务失效。 @Service public class OrderService { public void placeOrder() { this.updateStock(); // this 调用不经过代理,事务失效 } @Transactional public void updateStock() { ... } } 解决办法:把需要事务的方法拆到另一个 Bean 里,或注入自身代理(AopContext.currentProxy(),需要 exposeProxy=true)。 ...

Created 2026-02-02 · Updated 1016-07-01 · 2 min · 219 words · -

Spring Boot

Spring Boot 是什么 Spring Boot 是 Pivotal (现为 VMware/Broadcom)在 2014 年推出的框架,建立在 Spring Framework 之上,目标是简化整个 Spring 生态的开发、配置和部署。它不只是简化 Spring MVC,同样简化了 Spring Data(数据库访问)、Spring Security(认证授权)、Spring Messaging(消息队列)等全家桶的配置。 核心理念是 “约定优于配置”(Convention over Configuration):框架提前定好"默认约定",只要遵循这些约定,就不需要写任何配置;只有想偏离默认行为时,才需要显式配置。 例如,classpath 里有 spring-boot-starter-web,Spring Boot 就约定你要启动一个 Web 服务,自动完成:注册 DispatcherServlet、内嵌 Tomcat 监听 8080 端口、注册 Jackson 用于 JSON 序列化。你什么都不写,java -jar app.jar 就能跑起来。需要覆盖默认行为时,只在 src/main/resources/application.yml 中写偏离默认值的部分: server: port: 9090 # 只需声明偏离默认值的配置 也可通过命令行参数临时覆盖:java -jar app.jar --server.port=9090,优先级高于 application.yml。 出现背景 Spring Boot(2014)与微服务架构的兴起同期出现。2014 年 Martin Fowler 发表了微服务架构的奠基性文章,微服务要求每个服务独立部署、快速启动、进程隔离。传统的 WAR 包 + 外部 Tomcat 的部署方式与这一需求存在明显矛盾,Spring Boot 正是为了解决这一问题而生。 ...

Created 11116-05-11 · Updated 30306-06-30 · 9 min · 1853 words · wiloon

Spring CGLIB 动态代理

CGLIB(Code Generation Library)是一个运行期生成字节码的代码生成库,能在不实现接口的情况下,为一个类动态创建子类代理。Spring 内部大量依赖它做方法拦截(method interception)——无论是 AOP 代理还是 @Configuration 类的单例保证,背后用的都是 Spring 自己维护的一份 CGLIB fork(org.springframework.cglib),而不是外部独立发布的 cglib.jar。本文以 Spring 里的 CGLIB 为主线;原始独立 CGLIB 项目的来历、维护现状作为背景信息放在文末。 为什么需要 CGLIB:JDK 动态代理的限制 JDK 自 1.3 起自带动态代理(java.lang.reflect.Proxy),使用简单,但有一个硬性限制:被代理的类必须实现一个或多个接口,代理对象本质上是这些接口的另一份实现。如果要代理一个没有实现任何接口的普通类,JDK 动态代理就无能为力了——这正是 CGLIB 存在的原因。 CGLIB 的做法是:在运行期通过字节码处理框架 ASM,动态生成目标类的一个子类,重写其中的非 final 方法,在方法体里插入拦截逻辑,再调用原方法。因为是继承实现,所以不要求目标类实现接口,但也带来限制:类和方法不能是 final(无法被继承和重写),构造函数会被调用(生成的子类需要调用父类构造器)。 CGLIB 和 ASM 的分工:CGLIB 只关心「给目标类生成一个什么样的子类代理」这个业务语义层面的问题——该重写哪些方法、方法体里怎么织入拦截逻辑、生成的类怎么加载成 Class 对象并实例化;至于「怎么把这份子类描述翻译成合法的 .class 字节码」,全部委托给 ASM 完成。可以理解成:CGLIB 决定生成一个什么样的子类,ASM 负责把这个子类真正写成字节码——CGLIB 是构建在 ASM 之上、面向「动态生成子类代理」这个具体场景的应用层库,ASM 才是真正操作字节码指令的底层工具。 JDK 动态代理 CGLIB 实现方式 实现目标接口 生成目标类的子类 前提条件 目标类必须实现接口 目标类和方法不能是 final 底层机制 反射(InvocationHandler) ASM 生成字节码 典型使用方 Spring AOP(默认,接口存在时) Spring AOP(无接口时)、Hibernate 延迟加载、EasyMock/jMock Spring 如何使用 CGLIB:两个典型场景 1. Spring AOP 方法拦截 Spring AOP 优先用 JDK 动态代理;只有当目标类没有实现任何接口时,才回退(或显式配置 proxyTargetClass=true)使用 CGLIB 生成子类代理,在方法调用前后插入切面逻辑(比如 @Transactional 开启/提交事务)。 ...

Created 15156-12-15 · Updated 30306-06-30 · 2 min · 408 words · -

2026 W26

enx 加 Java 后端 最近投了 Java 方向的职位,这段时间在回忆和熟悉 Java/Spring,也在整理 blog 里之前攒下的资料。但只看文档、不动手,理解很有限。过去做 Java 项目时训练过的"生物神经网络"痕迹应该还在,细节被修剪掉了,主要的连接还在,得花点时间把细节重新接上。 enx 是我写的一个英文学习工具,也是技术栈的 playground。这周给 enx 加了一个 Spring Boot 后端,把一个简单的 API 迁了过去,依赖走 Homelab 里的 Nexus Maven 私服,构建和部署接到现有的 Tekton + k8s 流水线上:推代码后 Tekton 自动打镜像、更新到集群。这样一个最小闭环先跑起来,后面再慢慢补。 梳理 Java/Spring 文档 接着 W25 的节奏,继续整理 blog 里的 Java 文档,这周重心移到 Spring 和 JVM 周边。大脑像是索引和内存,blog 像是外部存储;脑子里的东西大概是 blog 内容的一个子集加上索引,有交叉,但也不是所有东西都写进了 blog。整理的过程就像是顺着索引把外存里的细节重新梳理一下。 这几个文档是本周动过的,方便以后自己回溯:classloader、Spring IoC 与 Spring Boot、graalvm native image、HotSpot,以及顺手补的 SPI / ServiceLoader 和 YAGNI。 公司:领照、刻章、开户 W24 注册了公司,这周把领营业执照、刻章办了,银行开户排到了下周。本来 6 月 24 日计划去领照,车启动打开导航才发现当天大连有达沃斯论坛限行,只好折回,在家准备面试和注册材料。第二天才正式跑完一圈。 ...

Created 28286-06-28 · Updated 30306-06-30 · 1 min · 150 words · -

Spring MVC

Spring MVC 是 Spring Framework 中负责处理 HTTP 请求的 Web 框架,实现了 MVC 设计模式。它是一个功能模块,而非独立框架。 本文专注 HTTP 处理与现用实践(注解映射、REST、校验等)。Spring Framework 整体定位、非 Web 场景(如 CLI)、早期 XML 配置、与 JDK 5 注解的关系、Web 层历史演变,见 Spring。 Spring MVC 与 Spring Boot 的关系 这两者经常被混淆,理清层次是关键。 层次关系 Spring Framework(基础框架) └── Spring MVC(Web 层模块,属于 Spring Framework 的一部分) Spring Boot(构建在 Spring Framework 之上的脚手架/工具) └── spring-boot-starter-web(包含 Spring MVC + 内嵌 Tomcat + Jackson) Spring MVC 是 Spring Framework 中负责处理 HTTP 请求的 Web 框架,实现了 MVC 设计模式。它是一个功能模块。 Spring Boot 是一个构建工具/脚手架,它并不替代 Spring MVC,而是让配置 Spring MVC(以及其他模块)变得更简单。 对比:传统 Spring MVC vs Spring Boot 方面 传统 Spring MVC Spring Boot 配置方式 XML(web.xml、applicationContext.xml)或 Java Config 自动配置,几乎零 XML 部署方式 打包为 WAR,部署到外部 Tomcat 打包为可执行 JAR,内嵌 Tomcat 依赖管理 手动指定每个依赖及版本,容易版本冲突 Starter 统一管理,版本经过验证 启动入口 通过 Servlet 容器启动 @SpringBootApplication 主类 + main() 方法 学习曲线 较陡,需理解大量 XML 配置 较平,约定优于配置 底层请求处理链路 无论是传统 Spring MVC + WAR,还是 Spring Boot + JAR,处理 HTTP 请求的调用链从未改变: ...

Created 30306-11-30 · Updated 27276-06-27 · 4 min · 810 words · -