Spring源码

BeanFactory与ApplicationContext的区别与联系

BeanFactory是ApplicationContext的父接口。ApplicationContext 实现都 [组合]了BeanFactory的功能。
ApplicationContext 比 BeanFactory 多实现了四个接口:
MessageSource: 国际化功能,支持多种语言
ResourcePatternResolver: 通配符匹配资源路径
EnvironmentCapable: 环境信息,系统环境变量,.properties、.application.yml等配置文件中的值
ApplicationEventPublisher: 发布事件对象

SpringBoot的run方法返回ConfigurableApplicationContext

ConfigurableApplicationContext 返回的beanFactory是DefaultListableBeanFactory类,其中获取单例对象的方法是由DefaultSingletonBeanFactory的成员变量singletonObjects获取的。

MessageSource

根据不同的语言配置文件,读取不同的语言信息
在resources目录下创建四个文件messages.propertes、messages_en.properties、messages_ja.properties、messages_zh.properties,然后分别在四个文件里面定义同名的key,比如在message_en.properties中定义hi=hello,在messages_ja.propertes中定义hi=こんにちは,在messages_zh中定义hi=你好,这样在代码中就可以根据这个key hi和不同的语言类型获取不同的value了。

System.out.println(context.getMessage("hi", null, Locale.CHINA));
System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
System.out.println(context.getMessage("hi", null, Locale.JAPANESE));

ResourcePatternResolver

获取类路径下的配置文件

Resource[] resources = context.getResources("classpath:messages*.properties");
for (Resource resource : resources) {
    System.out.println(resource);
}

EnvironmentCapable

获取系统环境变量中的java_home和项目的application.yml中的server.port属性

System.out.println(context.getEnvironment().getProperty("java_home"));
System.out.println(context.getEnvironment().getProperty("server.port"));

ApplicationEventPublisher

发布监听事件

定义一个用户注册事件类,继承自ApplicationEvent类
public class UserRegisteredEvent extends ApplicationEvent {
    public UserRegisteredEvent(Object source) {
        super(source);
    }
}
再定义一个监听器类,用于监听用户注册事件,类头上需要加@Component注解,将该类交给spring管理,定义一个处理事件的方法,参数类型为用户注册事件类的对象,方法头上需要加上@EventListener注解
@Component
@Slf4j
public class UserRegisteredListener {
    @EventListener
    public void userRegist(UserRegisteredEvent event) {
        System.out.println("UserRegisteredEvent...");
        log.debug("{}", event);
    }
}
接着再定义一个用户服务类,里面有个register(String username, String password)方法可以完成用户的注册,注册完毕后发布一下用户注册完毕事件。
@Component
@Slf4j
public class UserService {
    @Autowired
    private ApplicationEventPublisher context;
    public void register(String username, String password) {
        log.debug("新用户注册,账号:" + username + ",密码:" + password);
        context.publishEvent(new UserRegisteredEvent(this));
    }
}
最后在Springboot启动类中调用一下UserService里面的register()方法注册一个新用户,UserRegisteredListener中就能处理这个用户注册完毕的事件,实现了UserService类和UserRegisteredListener类的解耦。
UserService userService = context.getBean(UserService.class);
userService.register("张三", "123456");

BeanFactory 实现类

DefaultListableBeanFactory

创建Bean的过程:
1.Bean的定义

 // bean 的定义(即bean的一些描述信息,包含class:bean是哪个类,scope:单例还是多例,初始化、销毁方法等)
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();

2.注册Bean

 beanFactory.registerBeanDefinition("config", beanDefinition);

3.添加后处理器

 // 给 BeanFactory添加一些常用的后处理器,让它具备解析@Configuration、@Bean等注解的能力
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

4.执行bean工厂后处理器:@Configuration;@Bean

// 从bean工厂中取出BeanFactory的后处理器,并且执行这些后处理器
// BeanFactory 后处理器主要功能,补充了一些 bean 的定义        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values()
.forEach(beanFactoryPostProcessor -> {
            System.out.println(beanFactoryPostProcessor);
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});

5.执行Bean处理器:@Autowired;@Resource

beanFactory.addBeanPostProcessors(beanFactory.getBeansOfType(BeanPostProcessor.class)
.values().stream().sorted(beanFactory.getDependencyComparator())
.collect(Collectors.toCollection(ArrayList::new)));

@Autowired{类型};@Resource{名字}执行顺序
排序的依据是BeanPostProcessor内部的order属性

@Autowired
@Resource(name = "bean4")
private Inter bean3;
注入的是bean3,说明@Autowired生效

6.默认是延迟单例对象,使用它的时候才会进行构造创建对象实例

// 准备好所有单例,get()前就把对象初始化好
beanFactory.preInstantiateSingletons();

ApplicationContext接口的实现类

ClassPathXmlApplicationContext

//1.最为经典的容器,基于classpath 下 xml 格式的配置文件来创建
public void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context = 
        new ClassPathXmlApplicationContext("spring_bean.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
  }

FileSystemXmlApplicationContext

//2.基于磁盘路径下 xml 格式的配置文件来创建
public void testFileSystemXmlApplicationContext() {
 // 可以用绝对路径或者相对路径
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src\\main\\resources\\spring_bean.xml");

for (String name : context.getBeanDefinitionNames()) {
      System.out.println(name);
 }
   System.out.println(context.getBean(Bean2.class).getBean1());
}

ClassPathXmlApplicationContextFileSystemXmlApplicationContext底层原理
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(
new FileSystemResource("src\\main\\resources\\spring_bean.xml"));

AnnotationConfigApplicationContext

//3.较为经典的容器,基于java配置类来创建
public void testAnnotationConfigApplicationContext() {
        // 会自动加上5个后处理器
        // 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
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }

AnnotationConfigServletWebServerApplication

//4.较为经典的容器,基于java配置类来创建,并且还可以用于web环境
// 模拟了 springboot web项目内嵌Tomcat的工作原理
public void testAnnotationConfigServletWebServerApplicationContext() throws IOException {
        AnnotationConfigServletWebServerApplicationContext context = 
        new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        // 防止程序终止
        System.in.read();
    }
}

@Configuration
class WebConfig {
    @Bean
    // 1. WebServer工厂
    public ServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

    @Bean
    // 2. web项目必备的DispatcherServlet
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    @Bean
    // 3. 将DispatcherServlet注册到WebServer上
    public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
        return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
    }

    @Bean("/hello")
    public Controller controller1() {
        return (request, response) -> {
            response.getWriter().println("hello");
            return null;
        };
    }
}

Bean的生命周期

@Component
@Slf4j
public class LifeCycleBean {
    public LifeCycleBean() {
        log.debug("构造");
    }

    @Autowired
    public void autowire(@Value("${JAVA_HOME}") String name) {
        log.debug("依赖注入:{}", name);
    }

    @PostConstruct
    public void init() {
        log.debug("初始化");
    }

    @PreDestroy
    public void destroy() {
        log.debug("销毁");
    }
}
执行顺序:构造,依赖注入,初始化,销毁

编写自定义Bean的后处理器,需要实现InstantiationAwareBeanPostProcessor和DestructionAwareBeanPostProcessor接口,并加上@Component注解,对lifeCycleBean的生命周期过程进行扩展。

@Slf4j
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {

    @Override
    // 实例化前(即调用构造方法前)执行的方法
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            log.debug("<<<<<<<<<<< 实例化前执行,如@PreDestroy");
        // 返回null保持原有对象不变,返回不为null,会替换掉原有对象
        return null;
    }

    @Override
    // 实例化后执行的方法
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")) {
            log.debug("<<<<<<<<<<< 实例化后执行,这里如果返回 false 会跳过依赖注入阶段");
            // return false;
        }

        return true;
    }

    @Override
    // 依赖注入阶段执行的方法
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            log.debug("<<<<<<<<<<< 依赖注入阶段执行,如@Autowired、@Value、@Resource");
        return pvs;
    }

    @Override
    // 销毁前执行的方法
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBean"))
            log.debug("<<<<<<<<<<<销毁之前执行");
    }

    @Override
    // 初始化之前执行的方法
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBean"))
            log.debug("<<<<<<<<<<< 初始化之前执行,这里返回的对象会替换掉原本的bean,如 @PostConstruct、@ConfigurationProperties");
        return bean;
    }

    @Override
    // 初始化之后执行的方法
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBean"))
            log.debug("<<<<<<<<<<< 初始化之后执行,这里返回的对象会替换掉原本的bean,如 代理增强");
        return bean;
    }
}

模板方法

模板方法:将可扩展的位置留坑,然后定义一个接口,实现接口并加入链表中

public class TestMethodTemplatePattern {
    public static void main(String[] args) {
        MyBeanFactory beanFactory = new MyBeanFactory();
        beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
        beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
        beanFactory.getBean();
    }

    static class MyBeanFactory {
        public Object getBean() {
            Object bean = new Object();
            System.out.println("构造:" + bean);
            System.out.println("依赖注入:" + bean);
            for (BeanPostProcessor processor : processors) {
                processor.inject(bean);
            }
            System.out.println("初始化:" + bean);
            return bean;
        }

        private List<BeanPostProcessor> processors = new ArrayList<>();

        public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
            processors.add(beanPostProcessor);
        }
    }

    interface BeanPostProcessor {
        void inject(Object bean);
    }
}

Bean后处理器

Bean后处理器:为Bean生命周期各个阶段提供扩展
GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试。

@Slf4j
public class TestBeanPostProcessor {
    @Test
    public void testBeanPostProcessor() throws Exception {
        // GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
        // 这里用DefaultListableBeanFactory也可以完成测试,只是会比使用GenericApplicationContext麻烦一些
        GenericApplicationContext context = new GenericApplicationContext();

        // 用原始方法注册三个Bean
        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);
        context.registerBean("bean4", Bean4.class);

        // 设置解析 @Value 注解的解析器
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        // 添加解析 @Autowired 和 @Value 注解的后处理器
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        // 添加解析 @Resource、@PostConstruct、@PreDestroy 注解的后处理器
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        // 添加解析 @ConfigurationProperties注解的后处理器
        // ConfigurationPropertiesBindingPostProcessor后处理器不能像上面几种后处理器那样用context直接注册上去
        // context.registerBean(ConfigurationPropertiesBindingPostProcessor.class);
        // 需要反着来注册一下
        ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());


        //初始化容器,执行beanFactory后处理器,添加bean后处理器,初始化所有单例
        context.refresh();
        System.out.println(context.getBean(Bean4.class));

        //销毁容器
        context.close();
    }
}

@Autowired bean后处理器执行分析

@Autowired注解解析用到的后处理器是AutowiredAnnotationBeanPostProcessor

1.扫描被@Autowired标识的属性,封装成InjectionMetadata。

2.调用inject方法按类型查找值并使用反射进行赋值

​ a.反射获取到标识的属性

​ b.将这个属性封装成DependencyDescriptor对象

​ c.执行beanFactory的doResolveDependency获取到这个bean的值(前提该bean已注册)

​ d.给标识的属性进行赋值

Bean工厂后处理器

探究一下@Component、@ComponentScan、@Bean、@MapperScan这些注解分别是由哪个后处理器来解析的。

@Slf4j
public class TestBeanFactoryPostProcessors {
    @Test
    public void testBeanPostProcessors() throws IOException {
        // ⬇️GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("config", Config.class);
        // 添加Bean工厂后处理器ConfigurationClassPostProcessor
        // 解析@ComponentScan、@Bean、@Import、@ImportResource注解
        context.registerBean(ConfigurationClassPostProcessor.class);
        // 添加Bean工厂后处理器MapperScannerConfigurer,解析@MapperScan注解
        context.registerBean(MapperScannerConfigurer.class, beanDefinition -> {
            // 指定扫描的包名
            beanDefinition.getPropertyValues().add("basePackage", "top.jacktgq.mapper");
        });

        // ⬇️初始化容器
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // ⬇️销毁容器
        context.close();
    }
}

@Component、@Bean对应的Bean工厂后处理器是ConfigurationClassPostProcessor;
@MapperScan对应的Bean工厂后处理器是MapperScannerConfigurer

组件扫描过程原理

Bean工厂后处理器来解析@Component注解

1.查找某个类下的的某个注解对象

ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);

2.获取ComponentScan的包名进行转变路径

3.根据获取路径获取路径下的所有class资源

4.检查class资源是否加了@Component注解

5.注册为beanDefinition

6.将Bean定义加入工厂

Bean工厂后处理器来解析@Bean注解

1.读取有@Bean注解的类

2.获取被@Bean注解标识的方法

3.先有工厂对象(含有@Bean的类),再调用方法生产对象

4.获取beanDefinition

 // 这里不需要指定类名了,因为最终的BeanDefinition是Config类中加了@Bean属性的方法的返回值的类型的定义。
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
builder.setFactoryMethodOnBean(annotatedMethod.getMethodName(), "config");
//设置自动装配方法参数 
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
 if (initMethod.length() > 0) {
    builder.setInitMethodName(initMethod);
}

AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanFactory.registerBeanDefinition(annotatedMethod.getMethodName(), beanDefinition);

Bean工厂后处理器来解析@Mapper注解

1.获取被@Mapper注解标识的类资源
2.判断是否为接口类型
3.将该资源注册为beanDefinition

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class).addConstructorArgValue(classMetadata.getClassName()).setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE).getBeanDefinition();

4.注册

Aware和InitializingBean接口

Aware 接口用于注入一些与容器相关信息,例如:
a. BeanNameAware 注入 Bean 的名字
b. BeanFactoryAware 注入 BeanFactory 容器
c. ApplicationContextAware 注入 ApplicationContext 容器
d. EmbeddedValueResolverAware 注入 解析器,解析${}

public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {
    @Override
    public void setBeanName(String name) {
        log.debug("当前bean:" + this + ",实现 BeanNameAware 调用的方法,名字叫:" + name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.debug("当前bean:" + this + ",实现 ApplicationContextAware 调用的方法,容器叫:" + applicationContext);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.debug("当前bean:" + this + ",实现 InitializingBean 调用的方法,初始化");
    }

    @Autowired
    public void aaa(ApplicationContext applicationContext) {
        log.debug("当前bean:" + this +",使用 @Autowired 容器是:" + applicationContext);
    }

    @PostConstruct
    public void init() {
        log.debug("当前bean:" + this + ",使用 @PostConstruct 初始化");
    }
}
定义一个MyBean类,实现BeanNameAwareApplicationContextAwareInitializingBean接口并实现其方法,再定义两个方法,其中一个加@Autowired注解,注入ApplicationContext容器,另一个加@PostConstruct注解

b、c、d的功能用 @Autowired注解就能实现啊,为啥还要用 Aware 接口呢?
InititalizingBean 接口可以用 @PostConstruct注解实现,为啥还要用InititalizingBean呢?
简单地说:
@Autowired 和@PostConstruct注解的解析需要用到 Bean 后处理器,属于扩展功能,而 Aware 接口属于内置功能,不加任何扩展,Spring就能识别;
某些情况下,扩展功能会失效,而内置功能不会失效

@Autowired失效分析

在这里插入图片描述

Java 配置类包含 BeanFactoryPostProcessor 的情况
在这里插入图片描述

Aware 接口提供了一种【内置】 的注入手段,可以注入 BeanFactory,ApplicationContext;
InitializingBean 接口提供了一种 【内置】 的初始化手段;
内置的注入和初始化不收扩展功能的影响,总会被执行,因此 spring 框架内部的类常用它们。

Bean的初始化与销毁

初始化:执行优先级:@PostConstruct》InitializingBean》@Bean(initMethod)

@Slf4j
public class Bean1 implements InitializingBean {
    @PostConstruct
    public void init1() {
        log.debug("初始化1,@PostConstruct");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.debug("初始化2,InitializingBean接口");
    }

    public void init3() {
        log.debug("初始化3,@Bean的initMethod");
    }
}

销毁:

@Slf4j
public class Bean2 implements DisposableBean {
    @PreDestroy
    public void destroy1() {
        log.debug("销毁1,@PreDestory");
    }

    @Override
    public void destroy() throws Exception {
        log.debug("销毁2,DisposableBean接口");
    }

    public void destroy3() {
        log.debug("销毁3,@Bean的destroyMethod");
    }
}

对于init,三个初始化方法的执行顺序是

@PostConstruct -> InitializingBean接口 -> @Bean的initMethod

对于destory, 三个销毁方法的执行顺序是

@PreDestroy -> DisposableBean接口 -> @Bean的destroy

Scope类型

singleton:单例
prototype:多例
request:web请求
session:web的会话
application:web的ServletContext

Scope失效:单例注入多例,多例失效。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rw1CPkjP-1652622704291)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220515105829748.png)]

解决方法:

1.在SingletonBean的PrototypeBean1属性上加@Lazy注解

2.解决方法2:在PrototypeBean2的类上的@Scope注解多配置一个属性,如,@Scope(value = “prototype”, proxyMode = ScopedProxyMode.TARGET_CLASS)

3.解决方法3:使用ObjectFactory工厂类,在每次调用getProtypeBean3()方法中返回factory.getObject()

4.解决方法4:在SingletonBean中注入一个ApplicationContext,使用context.getBean(PrototypeBean4.class)获取对应的多例

AOP代理

aop是spring框架中非常重要的功能,其主要实现通常情况下是动态代理,但是这个说法并不全面,还有另外两种实现:

ajc编译器:是一种编译时的代码增强
agent类加载:一种类加载时的代码增强

aop之proxy增强-jdk

jdk的动态代理,只能针对接口代理

public class AopJdkProxyTest {
    @Test
    public void testJdkProxy() {
        // jdk的动态代理,只能针对接口代理
        // 目标对象
        Target target = new Target();
        // 用来加载在运行期间动态生成的字节码
        ClassLoader loader = AopJdkProxyTest.class.getClassLoader();
        Foo fooProxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, (proxy, method, args) -> {
            System.out.println("before...");
            Object result = method.invoke(target, args);
            System.out.println("after...");
            return result;  // 让代理也返回目标方法执行的结果
        });

        fooProxy.foo();
    }
}

interface Foo {
    void foo();
}

@Slf4j
final class Target implements Foo {
    public void foo() {
        log.debug("target foo");
    }
}

jdk动态代理总结:

代理对象和目标对象是兄弟关系,都实现了Foo接口,代理对象类型不能强转成目标对象类型;
目标类定义的时候可以加final修饰。

aop之proxy增强-cglib

public class AopCglibProxyTest {
    @Test
    public void testCglibProxy1() {
        // 目标对象
        Target target = new Target();
        Foo fooProxy = (Foo) Enhancer.create(Target.class, (MethodInterceptor) (obj, method, args, proxy) -> {
            System.out.println("before...");
            Object result = method.invoke(target, args); // 用方法反射调用目标
            System.out.println("after...");
            return result;
        });
        System.out.println(fooProxy.getClass());

        fooProxy.foo();
    }

    @Test
    public void testCglibProxy2() {
        // 目标对象
        Target target = new Target();
        Foo fooProxy = (Foo) Enhancer.create(Target.class, (MethodInterceptor) (obj, method, args, proxy) -> {
            System.out.println("before...");
            // proxy 它可以避免反射调用
            Object result = proxy.invoke(target, args); // 需要传目标类
            System.out.println("after...");
            return result;
        });
        System.out.println(fooProxy.getClass());

        fooProxy.foo();
    }

    @Test
    public void testCglibProxy3() {
        // 目标对象
        Foo fooProxy = (Foo) Enhancer.create(Target.class, (MethodInterceptor) (obj, method, args, proxy) -> {
            System.out.println("before...");
            // proxy 它可以避免反射调用
            Object result = proxy.invokeSuper(obj, args); // 不需要目标类,需要代理自己
            System.out.println("after...");
            return result;
        });
        System.out.println(fooProxy.getClass());

        fooProxy.foo();
    }
}

interface Foo {
    void foo();
}

@Slf4j
class Target implements Foo {
    public void foo() {
        log.debug("target foo");
    }
}

cglib动态代理总结:

代理类不需要实现接口;

代理对象和目标对象是父子关系,代理类继承于目标类;
目标类定义的时候不能加final修饰,否则代理类就无法继承目标类了,会报java.lang.IllegalArgumentException: Cannot subclass final class top.jacktgq.proxy.cglib.Target异常;
目标类方法定义的时候不能加final修饰,否则代理类继承目标类以后就不能重写目标类的方法了。

jdk代理原理:

// 增强处理器
public interface InvocationHandler {
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
// 代理接口
public interface Foo {
    void foo();
    int bar();
}
// 目标类
public final class Target implements Foo {
    public void foo() {
        System.out.println("target foo");
    }

    @Override
    public int bar() {
        System.out.println("target bar");
        return 1;
    }
}
//代理类
public class $Proxy0 implements Foo {
    static Method foo;
    static Method bar;

    static {
        try {
            foo = Foo.class.getDeclaredMethod("foo");
            bar = Foo.class.getDeclaredMethod("bar");
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }

    private InvocationHandler h;

    public $Proxy0(InvocationHandler h) {
        this.h = h;
    }

    @Override
    public void foo() {
        try {

            h.invoke(this, foo, new Object[0]);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public int bar() {
        try {
            return (int) h.invoke(this, bar, new Object[0]);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Foo proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
                // 1. 功能增强
                System.out.println("before...");
                // 2. 调用目标
                return method.invoke(new Target(), args);
            }
        });
        proxy.foo();
        System.out.println("bar()方法返回值:" + proxy.bar());
    }
}

spring直接代理生成class字节码代理对象

代理一点都不难,无非就是利用了多态、反射的知识

  1. 方法重写可以增强逻辑,只不过这【增强逻辑】千变万化,不能写死在代理内部
  2. 通过接口回调将【增强逻辑】置于代理类之外
  3. 配合接口方法反射(是多态调用),就可以再联动调用目标方法
  4. 会用 arthas 的 jad 工具反编译代理类
  5. 限制⛔:代理增强是借助多态来实现,因此成员变量、静态方法、final 方法均不能通过代理实现

方法反射优化

  1. 前 16 次反射性能较低
  2. 第 17 次调用会生成代理类,优化为非反射调用
  3. 会用 arthas 的 jad 工具反编译第 17 次调用生成的代理类

cglib 代理进阶

    Target target = new Target();
    Proxy proxy = new Proxy();
        
    proxy.setCallbacks(new Callback[]{(MethodInterceptor) (p, m, a, mp) -> {
            System.out.println("proxy before..." + mp.getSignature());
            // ⬇️调用目标方法(三种)
//            Object result = m.invoke(target, a);  // ⬅️反射调用
//            Object result = mp.invoke(target, a); // ⬅️非反射调用, 结合目标用
            Object result = mp.invokeSuper(p, a);   // ⬅️非反射调用, 结合代理用
            System.out.println("proxy after..." + mp.getSignature());
            return result;
        }});
        
        // ⬇️调用代理方法
        proxy.save();
  1. 回调的接口换了一下,InvocationHandler 改成了 MethodInterceptor
  2. 调用目标时有所改进,见下面代码片段
    1. method.invoke 是反射调用,必须调用到足够次数才会进行优化
    2. methodProxy.invoke 是不反射调用,它会正常(间接)调用目标对象的方法(Spring 采用)
      态方法、final 方法均不能通过代理实现
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值