0%

大致整理下面这些类的作用和关系:

BeanPostProcessor Bean初始化的后置处理器;
BeanFactoryPostProcessor BeanFactory的后置处理器;
BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的子接口, 新增了一个方法!

1. BeanPostProcessor

Bean初始化的后置处理器
postProcessBeforeInitialization() 在bean初始化前执行;
postProcessAfterInitialization() 在bean初始化完成后执行;

BeanPostProcessor 默认是会对整个Spring容器中所有的bean进行处理; 可以根据参数 bean和 beanName做一些选择和拦截操作, 比如为某个bean设一个值;

package com.niewj.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * 通过 BeanPostProcessor 接口
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        System.out.println("MyBeanPostProcessor-初始化!");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 可以通过此方法, 找到某一个目标 bean, 做一些操作: 如给容器中的 Service1 依赖的空对象赋值
        // 注意: 这里的 Service1.setService2(new Service2()) 中的 Service2 不会注册到容器中!
        // 但是 在Service1中使用 Service2的方法时, 是有我们赋值的对象的;
        System.out.println("###->MyBeanPostProcessor#postProcessBeforeInitialization->beanName=[" + beanName + "]###-> begin");
        if (bean instanceof Service1) {
            Service1 service1 = (Service1) bean;
            System.out.println("bean=" + bean + "; bean依赖为: " + service1.getService2());
            // 注入依赖(自己new的)
            service1.setService2(new Service2());
        }
        System.out.println("###->MyBeanPostProcessor#postProcessBeforeInitialization->beanName=[" + beanName + "]###-> end");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 由于上面已经赋值, 这里可以拿到
        System.out.println("###->MyBeanPostProcessor#postProcessAfterInitialization->beanName=[" + beanName + "]###-> begin");
        if (bean instanceof Service1) {
            Service1 service1 = (Service1) bean;
            System.out.println("bean=" + bean + "; bean依赖为: " + service1.getService2());
        }
        System.out.println("###->MyBeanPostProcessor#postProcessAfterInitialization->beanName=[" + beanName + "]###-> end");
        return bean;
    }
}

2. BeanFactoryPostProcessor

相比较 BeanPostProcessor, 它是针对 BeanFactory的;

BeanFactoryPostProcessor的执行时机是: 在Bean定义保存加载完成, bean尚未初始化前执行;

要先于 BeanPostProcessor的两个方法;

但是要晚于 BeanDefinitionRegistryPostProcessor 的另一个方法: postProcessBeanDefinitionRegistry()

具体参见 BeanDefinitionRegistryPostProcessor

package com.niewj.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("===> MyBeanFactoryPostProcessor#postProcessBeanFactory-->可以获取容器内bean定义的数量->getBeanDefinitionCount=> " + beanFactory.getBeanDefinitionCount());
        System.out.println("===> MyBeanFactoryPostProcessor#postProcessBeanFactory-->可以打印容器中的所有 定义的BeanDefinition->getBeanDefinitionNames:");
        System.out.println(Arrays.asList(beanFactory.getBeanDefinitionNames()));
    }
}

3. BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor 是上面 BeanFactoryPostProcessor 的子接口;

它除了有方法 postProcessBeanFactory()之外, 自己还新增了一个方法 postProcessBeanDefinitionRegistry

他们的执行时机:

postProcessBeanDefinitionRegistry()方法的执行时机是: 容器中所有的bean定义将要被加载前! 可以获取到 bean定义的注册器, 可用于注册bean;

postProcessBeanFactory() 方法的执行时机是: 容器中所有的bean已经保存加载, 但bean还未创建! 可以用来从beanFactory中拿出 bean;

package com.niewj.util;

import com.niewj.bean.Pojo4;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("===> MyBeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 调用!!!");
        System.out.println("registry instanceof BeanFactory: " + (registry instanceof BeanFactory));

        System.out.println("###->MyBeanDefinitionRegistryPostProcessor注册bean:[Service2.class]###-> begin");
        // 注册一个bean: Service2(并没有注解 @Component)
        AbstractBeanDefinition myBean = BeanDefinitionBuilder.rootBeanDefinition(Service2.class).getBeanDefinition();
        registry.registerBeanDefinition("service2", myBean);
        System.out.println("###->MyBeanDefinitionRegistryPostProcessor注册bean:[Service2.class]###-> over");

        System.out.println("###->MyBeanDefinitionRegistryPostProcessor注册bean:[Pojo4.class]###-> begin");
        // 注册一个bean: Pojo4
        AbstractBeanDefinition myPojo4 = BeanDefinitionBuilder.rootBeanDefinition(Pojo4.class).getBeanDefinition();
        registry.registerBeanDefinition("myPojo4", myPojo4);
        System.out.println("###->MyBeanDefinitionRegistryPostProcessor注册bean:[Pojo4.class]###-> over");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 1. 可以再次修改容器内一些bean的特征: 如设置 Pojo4类延迟初始化!
        BeanDefinition myPojo4 = beanFactory.getBeanDefinition("myPojo4");
        myPojo4.setLazyInit(true);

        // 2. 可以获取容器内bean定义的数量
        System.out.println("===> MyBeanDefinitionRegistryPostProcessor#postProcessBeanFactory-->可以获取容器内bean定义的数量->getBeanDefinitionCount=> " + beanFactory.getBeanDefinitionCount());

        // 3. 可以打印容器中的所有 定义的BeanDefinition
        System.out.println("===> MyBeanDefinitionRegistryPostProcessor#postProcessBeanFactory-->可以打印容器中的所有 定义的BeanDefinition->getBeanDefinitionNames:\t");
        System.out.println(Arrays.asList(beanFactory.getBeanDefinitionNames()));
    }
}

像本例中 Test2Service 并未注解 @Component/@Service等; 通过注册器可以将普通bean注册到容器:

BeanDefinitionBuilder.rootBeanDefinition(Test2Service.class).getBeanDefinition();
registry.registerBeanDefinition(“test2Service”, myBean);

其他相关的类代码:

  • Service1.java
package com.niewj.util;

import org.springframework.stereotype.Component;

@Component
public class Service1 {

    public Service2 getService2() {
        return service2;
    }

    public void setService2(Service2 service2) {
        this.service2 = service2;
    }

    private Service2 service2;

    public void doBusiness(){
        System.out.println("Service1.doBusiness");
        service2.doSth();
    }

}
  • Service2.java
package com.niewj.util;

public class Service2 {

    public void doSth(){
        System.out.println("Service2.doSth: 执行了!");
    }
}
  • Pojo4.java
package com.niewj.bean;

public class Pojo4 {
    public Pojo4(){
        System.out.println("Pojo4[无注解java类] 初始化~~~");
    }
}
  • User.java
package com.niewj.bean;

import lombok.Data;

@Data
public class User {
    private String name;
    private String passwd;
    private boolean online ;

    public User(String name, String passwd, boolean online){
        System.out.println("User-初始化!");
        this.name = name;
        this.passwd = passwd;
        this.online = online;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", passwd='" + passwd + '\'' +
                ", online=" + online +
                '}';
    }
}
  • 配置类: TestBeanCreationConfig.java
package com.niewj.config;

import com.niewj.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "com.niewj.util")
public class TestBeanCreationConfig {

    @Bean
    public User user() {
        return new User("u", "122", false);
    }
}
  • 测试用例: BeanCreationTest.java
package com.niewj;

import com.niewj.config.TestBeanCreationConfig;
import com.niewj.util.Service1;
import com.niewj.util.Service2;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.stream.Stream;

/**
 * spring bean创建和初始化测试:
 *  BeanFactoryPostProcessor
 *  BeamDefinitionRegistryPostProcessor
 */
public class BeanCreationTest {

    @Test
    public void testBeanCreation() {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register(TestBeanCreationConfig.class);
        ctx.refresh();

        // 打印spring容器中的 BeanDefinition
        Stream.of(ctx.getBeanDefinitionNames()).forEach(e -> System.out.println(e));
        System.out.println("============Service1#doBusiness()=================");

        Service1 service1 = ctx.getBean(Service1.class);
        service1.doBusiness();
        System.out.println("======Service2#doSth()=====");
        Service2 service2 = ctx.getBean(Service2.class);
        service2.doSth();

        ctx.close();
    }
}
  • output: 控制台输出:
===> MyBeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 调用!!!
registry instanceof BeanFactory: true
###->MyBeanDefinitionRegistryPostProcessor注册bean:[Service2.class]###-> begin
###->MyBeanDefinitionRegistryPostProcessor注册bean:[Service2.class]###-> over
###->MyBeanDefinitionRegistryPostProcessor注册bean:[Pojo4.class]###-> begin
###->MyBeanDefinitionRegistryPostProcessor注册bean:[Pojo4.class]###-> over
===> MyBeanDefinitionRegistryPostProcessor#postProcessBeanFactory-->可以获取容器内bean定义的数量->getBeanDefinitionCount=> 13
===> MyBeanDefinitionRegistryPostProcessor#postProcessBeanFactory-->可以打印容器中的所有 定义的BeanDefinition->getBeanDefinitionNames:	
[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, testBeanCreationConfig, myBeanDefinitionRegistryPostProcessor, myBeanFactoryPostProcessor, myBeanPostProcessor, service1, user, service2, myPojo4]
===> MyBeanFactoryPostProcessor#postProcessBeanFactory-->可以获取容器内bean定义的数量->getBeanDefinitionCount=> 13
===> MyBeanFactoryPostProcessor#postProcessBeanFactory-->可以打印容器中的所有 定义的BeanDefinition->getBeanDefinitionNames:
[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, testBeanCreationConfig, myBeanDefinitionRegistryPostProcessor, myBeanFactoryPostProcessor, myBeanPostProcessor, service1, user, service2, myPojo4]
MyBeanPostProcessor-初始化!
###->MyBeanPostProcessor#postProcessBeforeInitialization->beanName=[testBeanCreationConfig]###-> begin
###->MyBeanPostProcessor#postProcessBeforeInitialization->beanName=[testBeanCreationConfig]###-> end
###->MyBeanPostProcessor#postProcessAfterInitialization->beanName=[testBeanCreationConfig]###-> begin
###->MyBeanPostProcessor#postProcessAfterInitialization->beanName=[testBeanCreationConfig]###-> end
###->MyBeanPostProcessor#postProcessBeforeInitialization->beanName=[service1]###-> begin
bean=com.niewj.util.Service1@77167fb7; bean依赖为: null
###->MyBeanPostProcessor#postProcessBeforeInitialization->beanName=[service1]###-> end
###->MyBeanPostProcessor#postProcessAfterInitialization->beanName=[service1]###-> begin
bean=com.niewj.util.Service1@77167fb7; bean依赖为: com.niewj.util.Service2@1fe20588
###->MyBeanPostProcessor#postProcessAfterInitialization->beanName=[service1]###-> end
User-初始化!
###->MyBeanPostProcessor#postProcessBeforeInitialization->beanName=[user]###-> begin
###->MyBeanPostProcessor#postProcessBeforeInitialization->beanName=[user]###-> end
###->MyBeanPostProcessor#postProcessAfterInitialization->beanName=[user]###-> begin
###->MyBeanPostProcessor#postProcessAfterInitialization->beanName=[user]###-> end
###->MyBeanPostProcessor#postProcessBeforeInitialization->beanName=[service2]###-> begin
###->MyBeanPostProcessor#postProcessBeforeInitialization->beanName=[service2]###-> end
###->MyBeanPostProcessor#postProcessAfterInitialization->beanName=[service2]###-> begin
###->MyBeanPostProcessor#postProcessAfterInitialization->beanName=[service2]###-> end
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
testBeanCreationConfig
myBeanDefinitionRegistryPostProcessor
myBeanFactoryPostProcessor
myBeanPostProcessor
service1
user
service2
myPojo4
============Service1#doBusiness()=================
Service1.doBusiness
Service2.doSth: 执行了!
======Service2#doSth()=====
Service2.doSth: 执行了!

4. 执行顺序解析

  1. BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 可以拿到 BeanDefinitionRegistry, 可用来注册bean; 这里注册了2个bean这里 Service2.classPojo4.class 1-6行

  2. BeanDefinitionRegistryPostProcessor#postProcessBeanFactory 可以拿到 BeanFactory ; 这里打印里已有的bean定义数量 和 BeanFactory里所有的bean定义内容; 7-9行

  3. BeanFactoryPostProcessor#postProcessBeanFactory 可以拿到 BeanFactory; 这里同样打印了bean定义数量和BeanFactory里所有的bean定义内容; 10-12行

    – 上面两个PostProcessor是BeanFactory相关的, 只会执行一次; 下面的 BPP(BeanPostProcessor)则不同, BPP是每个Bean都要过一遍; 可以用来对Bean进行过滤做一些拦截处理:

  4. 遍历: BeanPostProcessor#postProcessBeforeInitialization 这里输出了每个bean的 beanName; 并过滤了一个bean:Service1, 如果是它, 就给手动注入了一个Service2对象; 12-32行

  5. 遍历: BeanPostProcessor#postProcessAfterInitialization 这里输出了每个bean的 beanName; 并过滤了一个bean:Service1, 获取到它的Service2对象, 可以看到非null了; 12-32行

  6. 上面流程就是3个PostProcessor的顺序关系; 后面的 33-45行就是 Stream.of(ctx.getBeanDefinitionNames()).forEach(e -> System.out.println(e));打印的内容了;

5. 小结

3个PostProcessor的执行顺序:

(1). BeanDefinitionRegistryPostProcessor# postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) ;

(2). BeanFactoryPostProcessor#postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);

(3). BeanPostProcessor# postProcessBeforeInitialization(Object bean, String beanName)

(4). BeanPostProcessor# postProcessAfterInitialization(Object bean, String beanName)

(1). Bean的创建

bean的创建实际上就是指 构造方法的调用;

singleton(单例)bean -容器初始化时会预先调用, 除非标注了 @Lazy 注解指定懒加载(延迟创建);

prototype(原型)bean -当第一次调用 getBean方法时, 才会调用构造方法

(2). Bean的初始化和销毁-4种方法

bean的初始化, 指的是在构造方法调用之后, 对象的一些初始化操作;

bean的销毁, 指的是在spring容器关闭前, 对bean对象做的一些后续处理操作的调用;

Bean的初始化和销毁有一下几种方法:

(2.1) @Bean注解指定initMethod/destroyMethod;

bean: 普通java类, 其中定义了 方法名: init close

package com.niewj.bean;

public class LifeTestBean1 {
    private String value;

    public LifeTestBean1(String value){
        System.out.println("LifeTestBean1-初始化!");
        this.value = value;
    }

    public void init(){
        System.out.println("LifeTestBean1#init-调用!");
    }

    public void close(){
        System.out.println("LifeTestBean1#close-调用!");
    }
}

Life1Config配置类中: 通过 @Bean 的属性 指定了初始化和销毁方法:

  • initMethod=”init”
  • destroyMethod=”close”
package com.niewj.config;

import com.niewj.bean.LifeTestBean1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Life1Config {

    @Bean(value = "lifeBean1", initMethod = "init", destroyMethod = "close")
    public LifeTestBean1 lifeTestBean(){
        return  new LifeTestBean1("bean1");
    }
}

测试用例: testLifecycle

package com.niewj;

import com.niewj.bean.LifeTestBean1;
import com.niewj.config.Life1Config;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.stream.Stream;

/**
 * spring生命周期.
 */
public class LifecycleTest {

    @Test
    public void testLifecycle() {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Life1Config.class);

        // 打印spring容器中的 BeanDefinition
        Stream.of(ctx.getBeanDefinitionNames()).forEach(e-> System.out.println(e));
        System.out.println("=============================");
        LifeTestBean1 bean = ctx.getBean(LifeTestBean1.class);

        System.out.println(bean);

        ctx.close();
    }
}

​ 可以看到:

  • 构造方法会预先调用(单例bean);
  • 然后init方法被调用;
  • 最后上下文关闭时, close方法也被调用!
LifeTestBean1-初始化!
LifeTestBean1#init-调用!
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
life1Config
lifeBean1
=============================
com.niewj.bean.LifeTestBean1@7d3a22a9
LifeTestBean1#close-调用!

(2.2) InitializingBean/DisposableBean 接口;

bean: LifeTestBean2 implements InitializingBean, DisposableBean

package com.niewj.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

/**
 * 实现 InitializingBean && DisposableBean
 */
public class LifeTestBean2 implements InitializingBean, DisposableBean {
    private String value;

    public LifeTestBean2(String value){
        System.out.println("LifeTestBean2-初始化!");
        this.value = value;
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("LifeTestBean2#DisposableBean#destroy-调用!");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("LifeTestBean2#InitializingBean#afterPropertiesSet-调用!");
    }
}

配置类: Life2Config:

package com.niewj.config;

import com.niewj.bean.LifeTestBean2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Life2Config {

    @Bean
    public LifeTestBean2 lifeTestBean(){
        return  new LifeTestBean2("bean2");
    }
}

测试用例:

@Test
public void testLifecycle2() {
    // 1. 通过bean实现 InitializingBean和DisposableBean接口
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Life2Config.class);

    // 打印spring容器中的 BeanDefinition
    Stream.of(ctx.getBeanDefinitionNames()).forEach(e-> System.out.println(e));
    System.out.println("=============================");
    LifeTestBean2 bean = ctx.getBean(LifeTestBean2.class);

    System.out.println(bean);

    ctx.close();
}

output:

  • 构造方法调用(singleton 容器预先初始化);
  • InitializingBean#afterPropertiesSet调用;
  • 工厂关闭前: DisposableBean#destroy调用;
LifeTestBean2-初始化!
LifeTestBean2#InitializingBean#afterPropertiesSet-调用!
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
life2Config
lifeTestBean
=============================
com.niewj.bean.LifeTestBean2@7d3a22a9
LifeTestBean2#DisposableBean#destroy-调用!

(2.3) @PostConstruct/@PreDestroy 注解(JSR250);

bean: LifeTestBean3 注解: @PreDestroy PostConstruct

package com.niewj.bean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * 通过 JSR250注解 @PostConstruct && @PreDestroy
 */
public class LifeTestBean3 {
    private String value;

    public LifeTestBean3(String value) {
        System.out.println("LifeTestBean3-初始化!");
        this.value = value;
    }

    @PreDestroy
    public void doDestroy() {
        System.out.println("LifeTestBean3#doDestroy-调用!");
    }

    @PostConstruct
    public void doInit() {
        System.out.println("LifeTestBean3#doInit-调用!");
    }
}

配置类:

package com.niewj.config;

import com.niewj.bean.LifeTestBean3;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Life3Config {

    @Bean
    public LifeTestBean3 lifeTestBean() {
        return new LifeTestBean3("bean3");
    }
}

测试用例:

@Test
public void testLifecycle3() {
    // 1. 通过 JSR250注解 @PostConstruct && @PreDestroy
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Life3Config.class);

    // 打印spring容器中的 BeanDefinition
    Stream.of(ctx.getBeanDefinitionNames()).forEach(e-> System.out.println(e));
    System.out.println("=============================");
    LifeTestBean3 bean = ctx.getBean(LifeTestBean3.class);

    System.out.println(bean);

    ctx.close();
}

output:

  • 构造方法调用;
  • @PostConstruct标注的方法调用;
  • 上下文关闭时; @PreDestroy标注的方法被调用;
LifeTestBean3-初始化!
LifeTestBean3#doInit-调用!
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
life3Config
lifeTestBean
=============================
com.niewj.bean.LifeTestBean3@2a32de6c
LifeTestBean3#doDestroy-调用!

(2.4) BeanPostProcessor接口(作用范围广);

此接口对所有扫描到的bean都起作用:

实现: BeanPostProcessor 接口:

  • before-init : postProcessBeforeInitialization(Object bean, String beanName)
  • after-init: postProcessAfterInitialization(Object bean, String beanName)
package com.niewj.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * 通过 BeanPostProcessor 接口
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        System.out.println("MyBeanPostProcessor-初始化!");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor#postProcessBeforeInitialization-调用!->beanName=" + beanName + "; bean=" + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor#postProcessAfterInitialization-调用!->beanName=" + beanName + "; bean=" + bean);
        return bean;
    }
}

com.niewj.bean包下一个普通类:

package com.niewj.bean;

import org.springframework.stereotype.Component;

/**
 * 普通bean+@Component
 */
@Component
public class LifeTestBean4 {

    public LifeTestBean4() {
        System.out.println("LifeTestBean4-初始化!");
    }
}

配置类: Life4Config:

扫描范围: @ComponentScan(“com.niewj.bean”)

包括: LifeTestBean4.java && MyBeanPostProcessor.java

package com.niewj.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.niewj.bean")
public class Life4Config {

}

用例: 注册配置类: Life4Config

@Test
public void testLifecycle4() {
    // 1. 通过 实现 BeanPostProcesser 接口
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Life4Config.class);

    // 打印spring容器中的 BeanDefinition
    Stream.of(ctx.getBeanDefinitionNames()).forEach(e-> System.out.println(e));
    System.out.println("=============================");

    ctx.close();
}

output: 观察控制台:

MyBeanPostProcessor: postProcessBeforeInitialization/postProcessAfterInitialization

LifeTestBean4: postProcessBeforeInitialization/postProcessAfterInitialization

MyBeanPostProcessor-初始化!
MyBeanPostProcessor#postProcessBeforeInitialization-调用!->beanName=life4Config; bean=com.niewj.config.Life4Config$$EnhancerBySpringCGLIB$$684530bf@27c86f2d
MyBeanPostProcessor#postProcessAfterInitialization-调用!->beanName=life4Config; bean=com.niewj.config.Life4Config$$EnhancerBySpringCGLIB$$684530bf@27c86f2d
LifeTestBean4-初始化!
MyBeanPostProcessor#postProcessBeforeInitialization-调用!->beanName=lifeTestBean4; bean=com.niewj.bean.LifeTestBean4@197d671
MyBeanPostProcessor#postProcessAfterInitialization-调用!->beanName=lifeTestBean4; bean=com.niewj.bean.LifeTestBean4@197d671
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
life4Config
lifeTestBean4
myBeanPostProcessor
=============================

(2.5) bean的初始化小结

初始化和销毁有四种方式:

1. @Bean注解指定属性 initMethod/destroyMethod;

2. 普通bean实现 InitializingBean/DisposableBean接口;

3. 普通bean方法上标注 @PostConstruct/@PreDestroy注解;

4. 通用方法: 实现接口 BeanPostProcessor;

(2.6) 问题来了: 4种方式的优先级顺序是如何的?

上实例: LifeTestBeanAll.java

其中包含:

1.@PostConstruct/@PreDestroy 注解;

2.InitializingBean, DisposableBean接口的实现;

3.@Bean 指定 initMethod/destroyMethod方法;

4.MyBeanPostProcessor实现(在下方);

package com.niewj.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * 普通bean+@Component
 */
@Component
public class LifeTestBeanAll implements InitializingBean, DisposableBean {

    public LifeTestBeanAll() {
        System.out.println("LifeTestBeanAll 构造方法调用!");
    }

    @PostConstruct
    public void postConstruct(){
        System.out.println("LifeTestBeanAll#@PostConstruct 调用");
    }

    @PreDestroy
    public void preDestroy(){
        System.out.println("LifeTestBeanAll#@PreDestroy 调用");
    }

    public void init(){
        System.out.println("LifeTestBeanAll#@Bean(initMethod) 调用");
    }

    public void close(){
        System.out.println("LifeTestBeanAll#@Bean(destroyMethod) 调用");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("LifeTestBeanAll#Disposable 调用~~");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("LifeTestBeanAll#InitializingBean#调用!~");
    }
}

MyBeanPostProcessor:

package com.niewj.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * 通过 BeanPostProcessor 接口
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        System.out.println("MyBeanPostProcessor-初始化!");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor#postProcessBeforeInitialization-调用!->beanName=" + beanName + "; bean=" + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor#postProcessAfterInitialization-调用!->beanName=" + beanName + "; bean=" + bean);
        return bean;
    }
}

配置类:

package com.niewj.config;

import com.niewj.bean.LifeTestBeanAll;
import com.niewj.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.niewj.bean")
public class LifeAllConfig {

    @Bean(initMethod = "init", destroyMethod = "close")
    public LifeTestBeanAll lifeTestBeanAll(){
        return new LifeTestBeanAll();
    }
}

测试用例:

@Test
public void testLifecycleAll() {
    // 注释掉 LifeTestBean4#@Component以防干扰
    // 1. 通过 实现 BeanPostProcesser 接口
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(LifeAllConfig.class);

    // 打印spring容器中的 BeanDefinition
    Stream.of(ctx.getBeanDefinitionNames()).forEach(e-> System.out.println(e));
    System.out.println("=============================");

    ctx.close();
}

output: 关键地方来了:

MyBeanPostProcessor-初始化!
MyBeanPostProcessor#postProcessBeforeInitialization-调用!->beanName=lifeAllConfig; bean=com.niewj.config.LifeAllConfig$$EnhancerBySpringCGLIB$$77052e36@3d121db3
MyBeanPostProcessor#postProcessAfterInitialization-调用!->beanName=lifeAllConfig; bean=com.niewj.config.LifeAllConfig$$EnhancerBySpringCGLIB$$77052e36@3d121db3
LifeTestBeanAll 构造方法调用!
MyBeanPostProcessor#postProcessBeforeInitialization-调用!->beanName=lifeTestBeanAll; bean=com.niewj.bean.LifeTestBeanAll@6b26e945
LifeTestBeanAll#@PostConstruct 调用
LifeTestBeanAll#InitializingBean#调用!~
LifeTestBeanAll#@Bean(initMethod) 调用
MyBeanPostProcessor#postProcessAfterInitialization-调用!->beanName=lifeTestBeanAll; bean=com.niewj.bean.LifeTestBeanAll@6b26e945
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
lifeAllConfig
lifeTestBeanAll
myBeanPostProcessor
=============================
LifeTestBeanAll#@PreDestroy 调用
LifeTestBeanAll#Disposable 调用~~
LifeTestBeanAll#@Bean(destroyMethod) 调用

分析整理: 只看 lifeTestBeanAll:

1.BeanPostProcessor#postProcessBeforeInitialization首先调用;

2.@PostConstruct;

3.InitializingBean接口实现;

4.@Bean(initMethod)

5.BeanPostProcessor#postProcessAfterInitialization调用;

6.@PreDestroy

7.Disposable接口实现

8.@Bean(destroyMethod)

初始化顺序: BeanPostProcessor的before-init –> @PostConstruct注解 –> InitializingBean接口 –> @Bean注解指定的initMethod方法 –>BeanPostProcessor的after-init;

destroy的顺序: @PreDestroy注解 –> DisposableBean接口 – > @Bean(destroyMethod)

(2.7) 源码分析:doCreateBean

源码位置:

// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
doCreateBean(){...
    try {
	    populateBean(beanName, mbd, instanceWrapper);
	    exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
...
}

1. populateBean: 为bean属性赋值等操作;

2. initializeBean: (下面时序图中的操作)

// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
方法流程源码片段:
---方法名:
AbstractAutowireCapableBeanFactory#initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
(1). applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)
	1. 遍历并调用BeanPostProcessor#postProcessBeforeInitialization()
(2). invokeInitMethods(beanName, wrappedBean, mbd): 
    1. 调用 InitializingBean接口的 afterPropertiesSet()方法;
    2. 调用 invokeCustomInitMethod() --> @Bean(initMethod) 执行!
(3). applyBeanPostProcessorsAfterInitialization
	1. 调用 postProcessAfterInitialization()
2.1 applyBeanPostProcessorsBeforeInitialization
2.2 invokeInitMethods
2.3. applyBeanPostProcessorsAfterInitialization

时序图:
image.png

(3). BeanPostProcessor扩展

@Autowired注解:

AutowiredAnnotationBeanPostProcessor类–>处理 @Autowired 注解

@PostConstruct && @PreDestroy的实现

InitDestroyAnnotationBeanPostProcessor类实现 @PostConstruct @PreDestroy注解

org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization
{
	metadata.invokeInitMethods(bean, beanName);
}

invokeInitMethods:
{
element.invoke(target);
}

根据以上知识点, 便可以知道为什么4个初始化和销毁的方法的优先级顺序是 BeanPostProcessor#before->@PostConstruct->InitializingBean->@Bean(initMethod)->BeanPostProcessor#after了;

openjdk8的sun.misc.Unsafe.java源码

2. Unsafe源码搬运展示

/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.misc;

import java.security.*;
import java.lang.reflect.*;

import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;


/**
 * A collection of methods for performing low-level, unsafe operations.
 * Although the class and all methods are public, use of this class is
 * limited because only trusted code can obtain instances of it.
 *
 * @author John R. Rose
 * @see #getUnsafe
 */

public final class Unsafe {

    private static native void registerNatives();
    static {
        registerNatives();
        sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");
    }

    private Unsafe() {}

    private static final Unsafe theUnsafe = new Unsafe();

    /**
     * Provides the caller with the capability of performing unsafe
     * operations.
     *
     * <p> The returned <code>Unsafe</code> object should be carefully guarded
     * by the caller, since it can be used to read and write data at arbitrary
     * memory addresses.  It must never be passed to untrusted code.
     *
     * <p> Most methods in this class are very low-level, and correspond to a
     * small number of hardware instructions (on typical machines).  Compilers
     * are encouraged to optimize these methods accordingly.
     *
     * <p> Here is a suggested idiom for using unsafe operations:
     *
     * <blockquote><pre>
     * class MyTrustedClass {
     *   private static final Unsafe unsafe = Unsafe.getUnsafe();
     *   ...
     *   private long myCountAddress = ...;
     *   public int getCount() { return unsafe.getByte(myCountAddress); }
     * }
     * </pre></blockquote>
     *
     * (It may assist compilers to make the local variable be
     * <code>final</code>.)
     *
     * @exception  SecurityException  if a security manager exists and its
     *             <code>checkPropertiesAccess</code> method doesn't allow
     *             access to the system properties.
     */
    @CallerSensitive
    public static Unsafe getUnsafe() {
        Class<?> caller = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(caller.getClassLoader()))
            throw new SecurityException("Unsafe");
        return theUnsafe;
    }

    /// peek and poke operations
    /// (compilers should optimize these to memory ops)

    // These work on object fields in the Java heap.
    // They will not work on elements of packed arrays.

    /**
     * Fetches a value from a given Java variable.
     * More specifically, fetches a field or array element within the given
     * object <code>o</code> at the given offset, or (if <code>o</code> is
     * null) from the memory address whose numerical value is the given
     * offset.
     * <p>
     * The results are undefined unless one of the following cases is true:
     * <ul>
     * <li>The offset was obtained from {@link #objectFieldOffset} on
     * the {@link java.lang.reflect.Field} of some Java field and the object
     * referred to by <code>o</code> is of a class compatible with that
     * field's class.
     *
     * <li>The offset and object reference <code>o</code> (either null or
     * non-null) were both obtained via {@link #staticFieldOffset}
     * and {@link #staticFieldBase} (respectively) from the
     * reflective {@link Field} representation of some Java field.
     *
     * <li>The object referred to by <code>o</code> is an array, and the offset
     * is an integer of the form <code>B+N*S</code>, where <code>N</code> is
     * a valid index into the array, and <code>B</code> and <code>S</code> are
     * the values obtained by {@link #arrayBaseOffset} and {@link
     * #arrayIndexScale} (respectively) from the array's class.  The value
     * referred to is the <code>N</code><em>th</em> element of the array.
     *
     * </ul>
     * <p>
     * If one of the above cases is true, the call references a specific Java
     * variable (field or array element).  However, the results are undefined
     * if that variable is not in fact of the type returned by this method.
     * <p>
     * This method refers to a variable by means of two parameters, and so
     * it provides (in effect) a <em>double-register</em> addressing mode
     * for Java variables.  When the object reference is null, this method
     * uses its offset as an absolute address.  This is similar in operation
     * to methods such as {@link #getInt(long)}, which provide (in effect) a
     * <em>single-register</em> addressing mode for non-Java variables.
     * However, because Java variables may have a different layout in memory
     * from non-Java variables, programmers should not assume that these
     * two addressing modes are ever equivalent.  Also, programmers should
     * remember that offsets from the double-register addressing mode cannot
     * be portably confused with longs used in the single-register addressing
     * mode.
     *
     * @param o Java heap object in which the variable resides, if any, else
     *        null
     * @param offset indication of where the variable resides in a Java heap
     *        object, if any, else a memory address locating the variable
     *        statically
     * @return the value fetched from the indicated Java variable
     * @throws RuntimeException No defined exceptions are thrown, not even
     *         {@link NullPointerException}
     */
    public native int getInt(Object o, long offset);

    /**
     * Stores a value into a given Java variable.
     * <p>
     * The first two parameters are interpreted exactly as with
     * {@link #getInt(Object, long)} to refer to a specific
     * Java variable (field or array element).  The given value
     * is stored into that variable.
     * <p>
     * The variable must be of the same type as the method
     * parameter <code>x</code>.
     *
     * @param o Java heap object in which the variable resides, if any, else
     *        null
     * @param offset indication of where the variable resides in a Java heap
     *        object, if any, else a memory address locating the variable
     *        statically
     * @param x the value to store into the indicated Java variable
     * @throws RuntimeException No defined exceptions are thrown, not even
     *         {@link NullPointerException}
     */
    public native void putInt(Object o, long offset, int x);

    /**
     * Fetches a reference value from a given Java variable.
     * @see #getInt(Object, long)
     */
    public native Object getObject(Object o, long offset);

    /**
     * Stores a reference value into a given Java variable.
     * <p>
     * Unless the reference <code>x</code> being stored is either null
     * or matches the field type, the results are undefined.
     * If the reference <code>o</code> is non-null, car marks or
     * other store barriers for that object (if the VM requires them)
     * are updated.
     * @see #putInt(Object, int, int)
     */
    public native void putObject(Object o, long offset, Object x);

    /** @see #getInt(Object, long) */
    public native boolean getBoolean(Object o, long offset);
    /** @see #putInt(Object, int, int) */
    public native void    putBoolean(Object o, long offset, boolean x);
    /** @see #getInt(Object, long) */
    public native byte    getByte(Object o, long offset);
    /** @see #putInt(Object, int, int) */
    public native void    putByte(Object o, long offset, byte x);
    /** @see #getInt(Object, long) */
    public native short   getShort(Object o, long offset);
    /** @see #putInt(Object, int, int) */
    public native void    putShort(Object o, long offset, short x);
    /** @see #getInt(Object, long) */
    public native char    getChar(Object o, long offset);
    /** @see #putInt(Object, int, int) */
    public native void    putChar(Object o, long offset, char x);
    /** @see #getInt(Object, long) */
    public native long    getLong(Object o, long offset);
    /** @see #putInt(Object, int, int) */
    public native void    putLong(Object o, long offset, long x);
    /** @see #getInt(Object, long) */
    public native float   getFloat(Object o, long offset);
    /** @see #putInt(Object, int, int) */
    public native void    putFloat(Object o, long offset, float x);
    /** @see #getInt(Object, long) */
    public native double  getDouble(Object o, long offset);
    /** @see #putInt(Object, int, int) */
    public native void    putDouble(Object o, long offset, double x);

    /**
     * This method, like all others with 32-bit offsets, was native
     * in a previous release but is now a wrapper which simply casts
     * the offset to a long value.  It provides backward compatibility
     * with bytecodes compiled against 1.4.
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public int getInt(Object o, int offset) {
        return getInt(o, (long)offset);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public void putInt(Object o, int offset, int x) {
        putInt(o, (long)offset, x);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public Object getObject(Object o, int offset) {
        return getObject(o, (long)offset);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public void putObject(Object o, int offset, Object x) {
        putObject(o, (long)offset, x);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public boolean getBoolean(Object o, int offset) {
        return getBoolean(o, (long)offset);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public void putBoolean(Object o, int offset, boolean x) {
        putBoolean(o, (long)offset, x);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public byte getByte(Object o, int offset) {
        return getByte(o, (long)offset);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public void putByte(Object o, int offset, byte x) {
        putByte(o, (long)offset, x);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public short getShort(Object o, int offset) {
        return getShort(o, (long)offset);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public void putShort(Object o, int offset, short x) {
        putShort(o, (long)offset, x);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public char getChar(Object o, int offset) {
        return getChar(o, (long)offset);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public void putChar(Object o, int offset, char x) {
        putChar(o, (long)offset, x);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public long getLong(Object o, int offset) {
        return getLong(o, (long)offset);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public void putLong(Object o, int offset, long x) {
        putLong(o, (long)offset, x);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public float getFloat(Object o, int offset) {
        return getFloat(o, (long)offset);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public void putFloat(Object o, int offset, float x) {
        putFloat(o, (long)offset, x);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public double getDouble(Object o, int offset) {
        return getDouble(o, (long)offset);
    }

    /**
     * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
     * See {@link #staticFieldOffset}.
     */
    @Deprecated
    public void putDouble(Object o, int offset, double x) {
        putDouble(o, (long)offset, x);
    }

    // These work on values in the C heap.

    /**
     * Fetches a value from a given memory address.  If the address is zero, or
     * does not point into a block obtained from {@link #allocateMemory}, the
     * results are undefined.
     *
     * @see #allocateMemory
     */
    public native byte    getByte(long address);

    /**
     * Stores a value into a given memory address.  If the address is zero, or
     * does not point into a block obtained from {@link #allocateMemory}, the
     * results are undefined.
     *
     * @see #getByte(long)
     */
    public native void    putByte(long address, byte x);

    /** @see #getByte(long) */
    public native short   getShort(long address);
    /** @see #putByte(long, byte) */
    public native void    putShort(long address, short x);
    /** @see #getByte(long) */
    public native char    getChar(long address);
    /** @see #putByte(long, byte) */
    public native void    putChar(long address, char x);
    /** @see #getByte(long) */
    public native int     getInt(long address);
    /** @see #putByte(long, byte) */
    public native void    putInt(long address, int x);
    /** @see #getByte(long) */
    public native long    getLong(long address);
    /** @see #putByte(long, byte) */
    public native void    putLong(long address, long x);
    /** @see #getByte(long) */
    public native float   getFloat(long address);
    /** @see #putByte(long, byte) */
    public native void    putFloat(long address, float x);
    /** @see #getByte(long) */
    public native double  getDouble(long address);
    /** @see #putByte(long, byte) */
    public native void    putDouble(long address, double x);

    /**
     * Fetches a native pointer from a given memory address.  If the address is
     * zero, or does not point into a block obtained from {@link
     * #allocateMemory}, the results are undefined.
     *
     * <p> If the native pointer is less than 64 bits wide, it is extended as
     * an unsigned number to a Java long.  The pointer may be indexed by any
     * given byte offset, simply by adding that offset (as a simple integer) to
     * the long representing the pointer.  The number of bytes actually read
     * from the target address maybe determined by consulting {@link
     * #addressSize}.
     *
     * @see #allocateMemory
     */
    public native long getAddress(long address);

    /**
     * Stores a native pointer into a given memory address.  If the address is
     * zero, or does not point into a block obtained from {@link
     * #allocateMemory}, the results are undefined.
     *
     * <p> The number of bytes actually written at the target address maybe
     * determined by consulting {@link #addressSize}.
     *
     * @see #getAddress(long)
     */
    public native void putAddress(long address, long x);

    /// wrappers for malloc, realloc, free:

    /**
     * Allocates a new block of native memory, of the given size in bytes.  The
     * contents of the memory are uninitialized; they will generally be
     * garbage.  The resulting native pointer will never be zero, and will be
     * aligned for all value types.  Dispose of this memory by calling {@link
     * #freeMemory}, or resize it with {@link #reallocateMemory}.
     *
     * @throws IllegalArgumentException if the size is negative or too large
     *         for the native size_t type
     *
     * @throws OutOfMemoryError if the allocation is refused by the system
     *
     * @see #getByte(long)
     * @see #putByte(long, byte)
     */
    public native long allocateMemory(long bytes);

    /**
     * Resizes a new block of native memory, to the given size in bytes.  The
     * contents of the new block past the size of the old block are
     * uninitialized; they will generally be garbage.  The resulting native
     * pointer will be zero if and only if the requested size is zero.  The
     * resulting native pointer will be aligned for all value types.  Dispose
     * of this memory by calling {@link #freeMemory}, or resize it with {@link
     * #reallocateMemory}.  The address passed to this method may be null, in
     * which case an allocation will be performed.
     *
     * @throws IllegalArgumentException if the size is negative or too large
     *         for the native size_t type
     *
     * @throws OutOfMemoryError if the allocation is refused by the system
     *
     * @see #allocateMemory
     */
    public native long reallocateMemory(long address, long bytes);

    /**
     * Sets all bytes in a given block of memory to a fixed value
     * (usually zero).
     *
     * <p>This method determines a block's base address by means of two parameters,
     * and so it provides (in effect) a <em>double-register</em> addressing mode,
     * as discussed in {@link #getInt(Object,long)}.  When the object reference is null,
     * the offset supplies an absolute base address.
     *
     * <p>The stores are in coherent (atomic) units of a size determined
     * by the address and length parameters.  If the effective address and
     * length are all even modulo 8, the stores take place in 'long' units.
     * If the effective address and length are (resp.) even modulo 4 or 2,
     * the stores take place in units of 'int' or 'short'.
     *
     * @since 1.7
     */
    public native void setMemory(Object o, long offset, long bytes, byte value);

    /**
     * Sets all bytes in a given block of memory to a fixed value
     * (usually zero).  This provides a <em>single-register</em> addressing mode,
     * as discussed in {@link #getInt(Object,long)}.
     *
     * <p>Equivalent to <code>setMemory(null, address, bytes, value)</code>.
     */
    public void setMemory(long address, long bytes, byte value) {
        setMemory(null, address, bytes, value);
    }

    /**
     * Sets all bytes in a given block of memory to a copy of another
     * block.
     *
     * <p>This method determines each block's base address by means of two parameters,
     * and so it provides (in effect) a <em>double-register</em> addressing mode,
     * as discussed in {@link #getInt(Object,long)}.  When the object reference is null,
     * the offset supplies an absolute base address.
     *
     * <p>The transfers are in coherent (atomic) units of a size determined
     * by the address and length parameters.  If the effective addresses and
     * length are all even modulo 8, the transfer takes place in 'long' units.
     * If the effective addresses and length are (resp.) even modulo 4 or 2,
     * the transfer takes place in units of 'int' or 'short'.
     *
     * @since 1.7
     */
    public native void copyMemory(Object srcBase, long srcOffset,
                                  Object destBase, long destOffset,
                                  long bytes);
    /**
     * Sets all bytes in a given block of memory to a copy of another
     * block.  This provides a <em>single-register</em> addressing mode,
     * as discussed in {@link #getInt(Object,long)}.
     *
     * Equivalent to <code>copyMemory(null, srcAddress, null, destAddress, bytes)</code>.
     */
    public void copyMemory(long srcAddress, long destAddress, long bytes) {
        copyMemory(null, srcAddress, null, destAddress, bytes);
    }

    /**
     * Disposes of a block of native memory, as obtained from {@link
     * #allocateMemory} or {@link #reallocateMemory}.  The address passed to
     * this method may be null, in which case no action is taken.
     *
     * @see #allocateMemory
     */
    public native void freeMemory(long address);

    /// random queries

    /**
     * This constant differs from all results that will ever be returned from
     * {@link #staticFieldOffset}, {@link #objectFieldOffset},
     * or {@link #arrayBaseOffset}.
     */
    public static final int INVALID_FIELD_OFFSET   = -1;

    /**
     * Returns the offset of a field, truncated to 32 bits.
     * This method is implemented as follows:
     * <blockquote><pre>
     * public int fieldOffset(Field f) {
     *     if (Modifier.isStatic(f.getModifiers()))
     *         return (int) staticFieldOffset(f);
     *     else
     *         return (int) objectFieldOffset(f);
     * }
     * </pre></blockquote>
     * @deprecated As of 1.4.1, use {@link #staticFieldOffset} for static
     * fields and {@link #objectFieldOffset} for non-static fields.
     */
    @Deprecated
    public int fieldOffset(Field f) {
        if (Modifier.isStatic(f.getModifiers()))
            return (int) staticFieldOffset(f);
        else
            return (int) objectFieldOffset(f);
    }

    /**
     * Returns the base address for accessing some static field
     * in the given class.  This method is implemented as follows:
     * <blockquote><pre>
     * public Object staticFieldBase(Class c) {
     *     Field[] fields = c.getDeclaredFields();
     *     for (int i = 0; i < fields.length; i++) {
     *         if (Modifier.isStatic(fields[i].getModifiers())) {
     *             return staticFieldBase(fields[i]);
     *         }
     *     }
     *     return null;
     * }
     * </pre></blockquote>
     * @deprecated As of 1.4.1, use {@link #staticFieldBase(Field)}
     * to obtain the base pertaining to a specific {@link Field}.
     * This method works only for JVMs which store all statics
     * for a given class in one place.
     */
    @Deprecated
    public Object staticFieldBase(Class<?> c) {
        Field[] fields = c.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            if (Modifier.isStatic(fields[i].getModifiers())) {
                return staticFieldBase(fields[i]);
            }
        }
        return null;
    }

    /**
     * Report the location of a given field in the storage allocation of its
     * class.  Do not expect to perform any sort of arithmetic on this offset;
     * it is just a cookie which is passed to the unsafe heap memory accessors.
     *
     * <p>Any given field will always have the same offset and base, and no
     * two distinct fields of the same class will ever have the same offset
     * and base.
     *
     * <p>As of 1.4.1, offsets for fields are represented as long values,
     * although the Sun JVM does not use the most significant 32 bits.
     * However, JVM implementations which store static fields at absolute
     * addresses can use long offsets and null base pointers to express
     * the field locations in a form usable by {@link #getInt(Object,long)}.
     * Therefore, code which will be ported to such JVMs on 64-bit platforms
     * must preserve all bits of static field offsets.
     * @see #getInt(Object, long)
     */
    public native long staticFieldOffset(Field f);

    /**
     * Report the location of a given static field, in conjunction with {@link
     * #staticFieldBase}.
     * <p>Do not expect to perform any sort of arithmetic on this offset;
     * it is just a cookie which is passed to the unsafe heap memory accessors.
     *
     * <p>Any given field will always have the same offset, and no two distinct
     * fields of the same class will ever have the same offset.
     *
     * <p>As of 1.4.1, offsets for fields are represented as long values,
     * although the Sun JVM does not use the most significant 32 bits.
     * It is hard to imagine a JVM technology which needs more than
     * a few bits to encode an offset within a non-array object,
     * However, for consistency with other methods in this class,
     * this method reports its result as a long value.
     * @see #getInt(Object, long)
     */
    public native long objectFieldOffset(Field f);

    /**
     * Report the location of a given static field, in conjunction with {@link
     * #staticFieldOffset}.
     * <p>Fetch the base "Object", if any, with which static fields of the
     * given class can be accessed via methods like {@link #getInt(Object,
     * long)}.  This value may be null.  This value may refer to an object
     * which is a "cookie", not guaranteed to be a real Object, and it should
     * not be used in any way except as argument to the get and put routines in
     * this class.
     */
    public native Object staticFieldBase(Field f);

    /**
     * Detect if the given class may need to be initialized. This is often
     * needed in conjunction with obtaining the static field base of a
     * class.
     * @return false only if a call to {@code ensureClassInitialized} would have no effect
     */
    public native boolean shouldBeInitialized(Class<?> c);

    /**
     * Ensure the given class has been initialized. This is often
     * needed in conjunction with obtaining the static field base of a
     * class.
     */
    public native void ensureClassInitialized(Class<?> c);

    /**
     * Report the offset of the first element in the storage allocation of a
     * given array class.  If {@link #arrayIndexScale} returns a non-zero value
     * for the same class, you may use that scale factor, together with this
     * base offset, to form new offsets to access elements of arrays of the
     * given class.
     *
     * @see #getInt(Object, long)
     * @see #putInt(Object, long, int)
     */
    public native int arrayBaseOffset(Class<?> arrayClass);

    /** The value of {@code arrayBaseOffset(boolean[].class)} */
    public static final int ARRAY_BOOLEAN_BASE_OFFSET
            = theUnsafe.arrayBaseOffset(boolean[].class);

    /** The value of {@code arrayBaseOffset(byte[].class)} */
    public static final int ARRAY_BYTE_BASE_OFFSET
            = theUnsafe.arrayBaseOffset(byte[].class);

    /** The value of {@code arrayBaseOffset(short[].class)} */
    public static final int ARRAY_SHORT_BASE_OFFSET
            = theUnsafe.arrayBaseOffset(short[].class);

    /** The value of {@code arrayBaseOffset(char[].class)} */
    public static final int ARRAY_CHAR_BASE_OFFSET
            = theUnsafe.arrayBaseOffset(char[].class);

    /** The value of {@code arrayBaseOffset(int[].class)} */
    public static final int ARRAY_INT_BASE_OFFSET
            = theUnsafe.arrayBaseOffset(int[].class);

    /** The value of {@code arrayBaseOffset(long[].class)} */
    public static final int ARRAY_LONG_BASE_OFFSET
            = theUnsafe.arrayBaseOffset(long[].class);

    /** The value of {@code arrayBaseOffset(float[].class)} */
    public static final int ARRAY_FLOAT_BASE_OFFSET
            = theUnsafe.arrayBaseOffset(float[].class);

    /** The value of {@code arrayBaseOffset(double[].class)} */
    public static final int ARRAY_DOUBLE_BASE_OFFSET
            = theUnsafe.arrayBaseOffset(double[].class);

    /** The value of {@code arrayBaseOffset(Object[].class)} */
    public static final int ARRAY_OBJECT_BASE_OFFSET
            = theUnsafe.arrayBaseOffset(Object[].class);

    /**
     * Report the scale factor for addressing elements in the storage
     * allocation of a given array class.  However, arrays of "narrow" types
     * will generally not work properly with accessors like {@link
     * #getByte(Object, int)}, so the scale factor for such classes is reported
     * as zero.
     *
     * @see #arrayBaseOffset
     * @see #getInt(Object, long)
     * @see #putInt(Object, long, int)
     */
    public native int arrayIndexScale(Class<?> arrayClass);

    /** The value of {@code arrayIndexScale(boolean[].class)} */
    public static final int ARRAY_BOOLEAN_INDEX_SCALE
            = theUnsafe.arrayIndexScale(boolean[].class);

    /** The value of {@code arrayIndexScale(byte[].class)} */
    public static final int ARRAY_BYTE_INDEX_SCALE
            = theUnsafe.arrayIndexScale(byte[].class);

    /** The value of {@code arrayIndexScale(short[].class)} */
    public static final int ARRAY_SHORT_INDEX_SCALE
            = theUnsafe.arrayIndexScale(short[].class);

    /** The value of {@code arrayIndexScale(char[].class)} */
    public static final int ARRAY_CHAR_INDEX_SCALE
            = theUnsafe.arrayIndexScale(char[].class);

    /** The value of {@code arrayIndexScale(int[].class)} */
    public static final int ARRAY_INT_INDEX_SCALE
            = theUnsafe.arrayIndexScale(int[].class);

    /** The value of {@code arrayIndexScale(long[].class)} */
    public static final int ARRAY_LONG_INDEX_SCALE
            = theUnsafe.arrayIndexScale(long[].class);

    /** The value of {@code arrayIndexScale(float[].class)} */
    public static final int ARRAY_FLOAT_INDEX_SCALE
            = theUnsafe.arrayIndexScale(float[].class);

    /** The value of {@code arrayIndexScale(double[].class)} */
    public static final int ARRAY_DOUBLE_INDEX_SCALE
            = theUnsafe.arrayIndexScale(double[].class);

    /** The value of {@code arrayIndexScale(Object[].class)} */
    public static final int ARRAY_OBJECT_INDEX_SCALE
            = theUnsafe.arrayIndexScale(Object[].class);

    /**
     * Report the size in bytes of a native pointer, as stored via {@link
     * #putAddress}.  This value will be either 4 or 8.  Note that the sizes of
     * other primitive types (as stored in native memory blocks) is determined
     * fully by their information content.
     */
    public native int addressSize();

    /** The value of {@code addressSize()} */
    public static final int ADDRESS_SIZE = theUnsafe.addressSize();

    /**
     * Report the size in bytes of a native memory page (whatever that is).
     * This value will always be a power of two.
     */
    public native int pageSize();


    /// random trusted operations from JNI:

    /**
     * Tell the VM to define a class, without security checks.  By default, the
     * class loader and protection domain come from the caller's class.
     */
    public native Class<?> defineClass(String name, byte[] b, int off, int len,
                                       ClassLoader loader,
                                       ProtectionDomain protectionDomain);

    /**
     * Define a class but do not make it known to the class loader or system dictionary.
     * <p>
     * For each CP entry, the corresponding CP patch must either be null or have
     * the a format that matches its tag:
     * <ul>
     * <li>Integer, Long, Float, Double: the corresponding wrapper object type from java.lang
     * <li>Utf8: a string (must have suitable syntax if used as signature or name)
     * <li>Class: any java.lang.Class object
     * <li>String: any object (not just a java.lang.String)
     * <li>InterfaceMethodRef: (NYI) a method handle to invoke on that call site's arguments
     * </ul>
     * @params hostClass context for linkage, access control, protection domain, and class loader
     * @params data      bytes of a class file
     * @params cpPatches where non-null entries exist, they replace corresponding CP entries in data
     */
    public native Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches);


    /** Allocate an instance but do not run any constructor.
        Initializes the class if it has not yet been. */
    public native Object allocateInstance(Class<?> cls)
        throws InstantiationException;

    /** Lock the object.  It must get unlocked via {@link #monitorExit}. */
    public native void monitorEnter(Object o);

    /**
     * Unlock the object.  It must have been locked via {@link
     * #monitorEnter}.
     */
    public native void monitorExit(Object o);

    /**
     * Tries to lock the object.  Returns true or false to indicate
     * whether the lock succeeded.  If it did, the object must be
     * unlocked via {@link #monitorExit}.
     */
    public native boolean tryMonitorEnter(Object o);

    /** Throw the exception without telling the verifier. */
    public native void throwException(Throwable ee);


    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapObject(Object o, long offset,
                                                     Object expected,
                                                     Object x);

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapInt(Object o, long offset,
                                                  int expected,
                                                  int x);

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapLong(Object o, long offset,
                                                   long expected,
                                                   long x);

    /**
     * Fetches a reference value from a given Java variable, with volatile
     * load semantics. Otherwise identical to {@link #getObject(Object, long)}
     */
    public native Object getObjectVolatile(Object o, long offset);

    /**
     * Stores a reference value into a given Java variable, with
     * volatile store semantics. Otherwise identical to {@link #putObject(Object, long, Object)}
     */
    public native void    putObjectVolatile(Object o, long offset, Object x);

    /** Volatile version of {@link #getInt(Object, long)}  */
    public native int     getIntVolatile(Object o, long offset);

    /** Volatile version of {@link #putInt(Object, long, int)}  */
    public native void    putIntVolatile(Object o, long offset, int x);

    /** Volatile version of {@link #getBoolean(Object, long)}  */
    public native boolean getBooleanVolatile(Object o, long offset);

    /** Volatile version of {@link #putBoolean(Object, long, boolean)}  */
    public native void    putBooleanVolatile(Object o, long offset, boolean x);

    /** Volatile version of {@link #getByte(Object, long)}  */
    public native byte    getByteVolatile(Object o, long offset);

    /** Volatile version of {@link #putByte(Object, long, byte)}  */
    public native void    putByteVolatile(Object o, long offset, byte x);

    /** Volatile version of {@link #getShort(Object, long)}  */
    public native short   getShortVolatile(Object o, long offset);

    /** Volatile version of {@link #putShort(Object, long, short)}  */
    public native void    putShortVolatile(Object o, long offset, short x);

    /** Volatile version of {@link #getChar(Object, long)}  */
    public native char    getCharVolatile(Object o, long offset);

    /** Volatile version of {@link #putChar(Object, long, char)}  */
    public native void    putCharVolatile(Object o, long offset, char x);

    /** Volatile version of {@link #getLong(Object, long)}  */
    public native long    getLongVolatile(Object o, long offset);

    /** Volatile version of {@link #putLong(Object, long, long)}  */
    public native void    putLongVolatile(Object o, long offset, long x);

    /** Volatile version of {@link #getFloat(Object, long)}  */
    public native float   getFloatVolatile(Object o, long offset);

    /** Volatile version of {@link #putFloat(Object, long, float)}  */
    public native void    putFloatVolatile(Object o, long offset, float x);

    /** Volatile version of {@link #getDouble(Object, long)}  */
    public native double  getDoubleVolatile(Object o, long offset);

    /** Volatile version of {@link #putDouble(Object, long, double)}  */
    public native void    putDoubleVolatile(Object o, long offset, double x);

    /**
     * Version of {@link #putObjectVolatile(Object, long, Object)}
     * that does not guarantee immediate visibility of the store to
     * other threads. This method is generally only useful if the
     * underlying field is a Java volatile (or if an array cell, one
     * that is otherwise only accessed using volatile accesses).
     */
    public native void    putOrderedObject(Object o, long offset, Object x);

    /** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)}  */
    public native void    putOrderedInt(Object o, long offset, int x);

    /** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */
    public native void    putOrderedLong(Object o, long offset, long x);

    /**
     * Unblock the given thread blocked on <tt>park</tt>, or, if it is
     * not blocked, cause the subsequent call to <tt>park</tt> not to
     * block.  Note: this operation is "unsafe" solely because the
     * caller must somehow ensure that the thread has not been
     * destroyed. Nothing special is usually required to ensure this
     * when called from Java (in which there will ordinarily be a live
     * reference to the thread) but this is not nearly-automatically
     * so when calling from native code.
     * @param thread the thread to unpark.
     *
     */
    public native void unpark(Object thread);

    /**
     * Block current thread, returning when a balancing
     * <tt>unpark</tt> occurs, or a balancing <tt>unpark</tt> has
     * already occurred, or the thread is interrupted, or, if not
     * absolute and time is not zero, the given time nanoseconds have
     * elapsed, or if absolute, the given deadline in milliseconds
     * since Epoch has passed, or spuriously (i.e., returning for no
     * "reason"). Note: This operation is in the Unsafe class only
     * because <tt>unpark</tt> is, so it would be strange to place it
     * elsewhere.
     */
    public native void park(boolean isAbsolute, long time);

    /**
     * Gets the load average in the system run queue assigned
     * to the available processors averaged over various periods of time.
     * This method retrieves the given <tt>nelem</tt> samples and
     * assigns to the elements of the given <tt>loadavg</tt> array.
     * The system imposes a maximum of 3 samples, representing
     * averages over the last 1,  5,  and  15 minutes, respectively.
     *
     * @params loadavg an array of double of size nelems
     * @params nelems the number of samples to be retrieved and
     *         must be 1 to 3.
     *
     * @return the number of samples actually retrieved; or -1
     *         if the load average is unobtainable.
     */
    public native int getLoadAverage(double[] loadavg, int nelems);

    // The following contain CAS-based Java implementations used on
    // platforms not supporting native instructions

    /**
     * Atomically adds the given value to the current value of a field
     * or array element within the given object <code>o</code>
     * at the given <code>offset</code>.
     *
     * @param o object/array to update the field/element in
     * @param offset field/element offset
     * @param delta the value to add
     * @return the previous value
     * @since 1.8
     */
    public final int getAndAddInt(Object o, long offset, int delta) {
        int v;
        do {
            v = getIntVolatile(o, offset);
        } while (!compareAndSwapInt(o, offset, v, v + delta));
        return v;
    }

    /**
     * Atomically adds the given value to the current value of a field
     * or array element within the given object <code>o</code>
     * at the given <code>offset</code>.
     *
     * @param o object/array to update the field/element in
     * @param offset field/element offset
     * @param delta the value to add
     * @return the previous value
     * @since 1.8
     */
    public final long getAndAddLong(Object o, long offset, long delta) {
        long v;
        do {
            v = getLongVolatile(o, offset);
        } while (!compareAndSwapLong(o, offset, v, v + delta));
        return v;
    }

    /**
     * Atomically exchanges the given value with the current value of
     * a field or array element within the given object <code>o</code>
     * at the given <code>offset</code>.
     *
     * @param o object/array to update the field/element in
     * @param offset field/element offset
     * @param newValue new value
     * @return the previous value
     * @since 1.8
     */
    public final int getAndSetInt(Object o, long offset, int newValue) {
        int v;
        do {
            v = getIntVolatile(o, offset);
        } while (!compareAndSwapInt(o, offset, v, newValue));
        return v;
    }

    /**
     * Atomically exchanges the given value with the current value of
     * a field or array element within the given object <code>o</code>
     * at the given <code>offset</code>.
     *
     * @param o object/array to update the field/element in
     * @param offset field/element offset
     * @param newValue new value
     * @return the previous value
     * @since 1.8
     */
    public final long getAndSetLong(Object o, long offset, long newValue) {
        long v;
        do {
            v = getLongVolatile(o, offset);
        } while (!compareAndSwapLong(o, offset, v, newValue));
        return v;
    }

    /**
     * Atomically exchanges the given reference value with the current
     * reference value of a field or array element within the given
     * object <code>o</code> at the given <code>offset</code>.
     *
     * @param o object/array to update the field/element in
     * @param offset field/element offset
     * @param newValue new value
     * @return the previous value
     * @since 1.8
     */
    public final Object getAndSetObject(Object o, long offset, Object newValue) {
        Object v;
        do {
            v = getObjectVolatile(o, offset);
        } while (!compareAndSwapObject(o, offset, v, newValue));
        return v;
    }


    /**
     * Ensures lack of reordering of loads before the fence
     * with loads or stores after the fence.
     * @since 1.8
     */
    public native void loadFence();

    /**
     * Ensures lack of reordering of stores before the fence
     * with loads or stores after the fence.
     * @since 1.8
     */
    public native void storeFence();

    /**
     * Ensures lack of reordering of loads or stores before the fence
     * with loads or stores after the fence.
     * @since 1.8
     */
    public native void fullFence();

    /**
     * Throws IllegalAccessError; for use by the VM.
     * @since 1.8
     */
    private static void throwIllegalAccessError() {
       throw new IllegalAccessError();
    }

}

1. 假如数据库有表emp:

empno name   age
001      lucy      22
002      lily        null
003      lilei       null
004      lucy      null
005      pear      null
006      pear      null

当执行sql:

SELECT empno FROM `emp` where age != 22;

返回的竟然一条都没有;

结论:null值是不参与比较的, age != 22 , 所有null的那些列都被过滤去掉了.

关键时刻注意这个特性. 

2. SQL中,NULL值与任何值比较(即使是NULL)永不为“真”

包含NULL的表达式总是会导出NULL值  

“Mysql参考文档”:

包含NULL的表达式总是会导出NULL值


[2016-10-26]

数据库表:

select * from rec order by rst,game_time;

ID GAME_TIME RST
2 01-1月 -11 F
6 01-1月 -11 F
3 02-1月 -11 F
9 02-1月 -11 F
7 03-1月 -11 F
1 01-1月 -11 W
4 01-1月 -11 W
8 01-1月 -11 W
5 02-1月 -11 W

要求结果:

比赛日期 结果 结果统计
02-1月 -11 失败 2
03-1月 -11 失败 1
02-1月 -11 胜利 1
01-1月 -11 失败 2
01-1月 -11 胜利 3

写出SQL1:decode函数

select  
     game_time as 比赛日期,  
     decode(rst,'F','失败','W','胜利','无结果') as 结果,  
     count(rst) as 结果统计  
 from rec  
 group by game_time,rst; 

SQL2:case语句:

select   
game_time as 比赛日期,  
(case rst  when 'W' then '胜利'  
                when 'F' then '失败'  
                else '无结果'  
end)结果,  
count(rst) as 结果统计  
from rec  
group by game_time,rst;

记录下:

2. decode函数用法:

decode(表达式1,条件1,结果1[条件2,结果2][default]);

3. case 语句用法:

case 表达式
when 表达式1 then ....
when 表达式2 then ....
else  ......
end 表达式

—[2013-07-02]—