BeanFactory和ApplicationContext

笔记参考B站黑马程序员视频:spring原理

pom.xml配置如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.5</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

 

1.BeanFactory接口

打开一个springboot项目的启动类 可以看到启动类的run方法是有返回值的

ConfigurableApplicationContext 是 Spring 框架中的一个接口,扩展了 ApplicationContext 接口。 ctrl+Alt+U打开类图

如下

ApplicationContext是间接继承BeanFactory的 BeanFactory才是 Spring 的核心容器,主要的 ApplicationContext 实现都组合了它的功能 比如getBean方法

实际就是调用内部组合了BeanFactory的方法

BeanFactory的默认实现是DefaultListableBeanFactory

类图如下:

DefaultSingletonBeanRegistry 是 Spring 框架中用于管理单例 bean 的默认实现类。

在 Spring 容器中,bean 可以配置为单例(singleton)或原型(prototype)。对于单例 bean,Spring 将仅创建一个实例,并在需要时重复使用该实例。

DefaultSingletonBeanRegistry 负责跟踪和管理这些单例 bean 的创建和获取。

在类图上选中类,点击F4就可以跳转到源码

singletonObjects 是 DefaultSingletonBeanRegistry 类中用于缓存已经创建的单例 bean 实例。

这个缓存是一个 ConcurrentHashMap,它使用 bean 的名称作为键,bean 实例作为值。

 

2.ApplicationContext接口

ApplicationContext 提供了对应用程序中所有 bean 的管理功能,包括创建、配置、初始化和销毁 bean。

主要功能在这四个类中:

  • ResourcePatternResolver:用于根据路径模式加载多个资源。
  • ApplicationEventPublisher:用于发布应用事件。
  • EnvironmentCapable:指示对象能够访问 Environment,获取环境属性。
  • MessageSource:用于解析国际化消息。

 

1. MessageSource

MessageSource 支持国际化消息解析 在对应文件配置

这里存放通用的

这是英文

日文,当然可以写成日文

中文

对应方法是getMessage
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
System.out.println(context.getMessage("dreams", null, Locale.CHINA));
System.out.println(context.getMessage("dreams", null, Locale.ENGLISH));
System.out.println(context.getMessage("dreams", null, Locale.JAPANESE));

 

2.ApplicationEventPublisher

通过 ApplicationEventPublisher 支持事件发布和监听。 我们需要先创建一个事件类

package com.dreams.a01;

import org.springframework.context.ApplicationEvent;

public class UserRegisteredEvent extends ApplicationEvent {
    public UserRegisteredEvent(Object source) {
        super(source);
    }
}

发送

ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
context.publishEvent(new UserRegisteredEvent(context));

发布 UserRegisteredEvent 事件,由 Event02类自动进行处理 由 Event02类接收

package com.dreams.a01;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class Event02 {

    private static final Logger log = LoggerFactory.getLogger(Event02.class);

    @EventListener
    public void send(UserRegisteredEvent event) {
        log.debug("{}", event);
        log.debug("发送短信");
    }
}

例;

package com.dreams.a01;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class Event01 {

    private static final Logger log = LoggerFactory.getLogger(Event01.class);

    @Autowired
    private ApplicationEventPublisher context;

    public void register() {
        log.debug("用户注册");
        context.publishEvent(new UserRegisteredEvent(this));
    }

}

然后在启动类加入注册代码

context.getBean(Event01.class).register();

运行:

 

3.ResourcePatternResolver

通过ResourcePatternResolver支持访问各种类型的资源,如文件、URL 等。 对应方法是getResources 加载符合指定路径模式的所有资源

Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
    System.out.println(resource);
}

 

4.EnvironmentCapable

通过 EnvironmentCapable接口提供对环境变量和属性的访问。 对应方法是getEnvironment()

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

 

3.BeanFactory实现

DefaultListableBeanFactory 是 BeanFactory 接口的默认实现。 定义一些配置:

@Configuration
static class Config {
    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean
    public Bean2 bean2() {
        return new Bean2();
    }

    @Bean
    public Bean3 bean3() {
        return new Bean3();
    }

    @Bean
    public Bean4 bean4() {
        return new Bean4();
    }
}

interface Inter {

}

static class Bean3 implements Inter {

}

static class Bean4 implements Inter {

}

static class Bean1 {
    private static final Logger log = LoggerFactory.getLogger(Bean1.class);

    public Bean1() {
        log.debug("构造 Bean1()");
    }

    @Autowired
    private Bean2 bean2;

    public Bean2 getBean2() {
        return bean2;
    }

    @Autowired
    @Resource(name = "bean4")
    private Inter bean3;

    public Inter getInter() {
        return bean3;
    }
}

static class Bean2 {
    private static final Logger log = LoggerFactory.getLogger(Bean2.class);

    public Bean2() {
        log.debug("构造 Bean2()");
    }
}

根据上面的代码我们可以手动注册一个名为 “config” 的 Bean 定义 常用方法;

  • BeanDefinitionBuilder 是一个用于构建 Bean 定义的实用程序类。
  • genericBeanDefinition(Config.class) 表示创建一个通用的 Bean 定义,指定了 Bean 的类型为 Config。
  • setScope(“singleton”) 表示将 Bean 的作用域设置为 Singleton单例模式,即在容器中仅存在一个实例。
  • 使用 beanFactory.registerBeanDefinition() 方法注册了名为 “config” 的 Bean 定义,其中包含了上面定义的配置信息。

实例代码如下:

public static void main(String[] args) {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    // bean 的定义(class, scope, 初始化, 销毁)
    AbstractBeanDefinition beanDefinition =
            BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
    beanFactory.registerBeanDefinition("config", beanDefinition);

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

但是上面的配置了不止一个Bean,如下:

@Configuration
static class Config {
    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }
    //......
}

也就是对@Bean等注解的解析并不在该BeanFactory类。

AnnotationConfigUtils.registerAnnotationConfigProcessors() 方法,向 BeanFactory 添加一些常用的后处理器,这些后处理器用于处理注解配置。 然后还需要获取并执行所有注册的 BeanFactoryPostProcessor(Bean工厂处理器,下面输出的第一个处理器,但是第二第三不是),对 BeanFactory 中的 Bean 进行处理。

public static void main(String[] args) {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    // bean 的定义(class, scope, 初始化, 销毁)
    AbstractBeanDefinition beanDefinition =
            BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
    beanFactory.registerBeanDefinition("config", beanDefinition);

    // 给 BeanFactory 添加一些常用的后处理器
    AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

    // 此时还没有处理
    System.out.println("此时还没有处理 :");
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }



    // BeanFactoryPostProcessor后处理器主要功能为补充了一些 bean 定义
    // 获取并执行所有注册的 BeanFactoryPostProcessor,对 BeanFactory 中的 Bean 进行处理。
    beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream()
            .forEach(beanFactoryPostProcessor -> {
                beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
            });

    System.out.println("\n处理完成 :");
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }

}

上面的代码我们只使用了第一个处理器
在下面输出的Bean名称,除了我们定义的,其他就是后处理器

这些是 Spring 框架中常用的内部后处理器。

  • org.springframework.context.annotation.internalConfigurationAnnotationProcessor: 这个后处理器用于处理配置类上的注解,例如 @Configuration 注解。它会扫描并解析这些注解,将配置类转换为相应的 Bean 定义。
  • org.springframework.context.annotation.internalAutowiredAnnotationProcessor: 这个后处理器用于处理自动装配的注解,例如 @Autowired 和 @Resource 注解。它会扫描并解析这些注解,完成依赖注入的操作。
  • org.springframework.context.annotation.internalCommonAnnotationProcessor: 这个后处理器用于处理通用的注解,例如 JSR-250 规范中定义的注解,如 @PostConstruct 和 @PreDestroy,或者还有@Resource,它会扫描并解析这些注解,执行相应的初始化和销毁方法。
  • org.springframework.context.event.internalEventListenerProcessor: 这个后处理器用于处理事件监听器的注解,例如 @EventListener 注解。它会扫描并解析这些注解,将事件监听器注册到事件发布器中,以便在对应的事件发生时触发相应的处理逻辑。
  • org.springframework.context.event.internalEventListenerFactory: 这个后处理器用于创建事件监听器的适配器,使得事件监听器能够被正确地触发。它会根据监听器的类型和方法签名,创建适配器实例,并将其注册到事件发布器中。

我们只使用了第一个处理器,所以这时还没有执行自动注入

Bean2 bean2 = beanFactory.getBean(Bean1.class).getBean2();
System.out.println(bean2 != null? bean2 : "未注入");

再添加上BeanPostProcessor处理器

// BeanFactory 后处理器主要功能,补充了一些 bean 定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
    beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
        .forEach(beanPostProcessor -> {
    System.out.println(">>>>" + beanPostProcessor);
    beanFactory.addBeanPostProcessor(beanPostProcessor);
});

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

Bean2 bean2 = beanFactory.getBean(Bean1.class).getBean2();
System.out.println(bean2 != null? "注入成功 对象 :" + bean2 : "未注入");

这两个就是BeanPostProcessor。

默认是调用时才加载,也就是说虽然我们添加了处理器,但是不会去加载,而是等到比如调用getBean方法,才加载 注释上面调用的getBean方法,加入以下代码

System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());

加入下面代码

// 准备好所有单例
beanFactory.preInstantiateSingletons(); 
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());

如果一个属性同时使用了 @Autowired 和 @Resource 注解,通常情况下@Autowired 注解会生效。

具体来说,这是因为 @Resource 注解是由 CommonAnnotationBeanPostProcessor 处理的,而 @Autowired 注解是由 AutowiredAnnotationBeanPostProcessor 处理的。

如上图,在 Spring 的默认配置下,AutowiredAnnotationBeanPostProcessor优先级高于CommonAnnotationBeanPostProcessor ,因此@Autowired 注解会被优先处理。 如果想要更改优先级,加入:

.sorted(beanFactory.getDependencyComparator())

代码如下:

// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
        .sorted(beanFactory.getDependencyComparator())
        .forEach(beanPostProcessor -> {
    System.out.println(">>>>" + beanPostProcessor);
    beanFactory.addBeanPostProcessor(beanPostProcessor);
});

// 准备好所有单例
beanFactory.preInstantiateSingletons();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());

beanFactory.getDependencyComparator() 方法用于获取一个 Comparator 对象,该对象可以用来对 Bean 进行排序。 上面我们使用添加后处理器的方法

进入源码

 

4.ApplicationContext实现

ApplicationContext 有多种常用的实现类: ClassPathXmlApplicationContext:从类路径下的 XML 配置文件中加载上下文定义,适合相对独立的应用程序。

// 较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建
private static void testClassPathXmlApplicationContext() {
    ClassPathXmlApplicationContext context =
            new ClassPathXmlApplicationContext("a02.xml");

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

    System.out.println(context.getBean(Bean2.class).getBean1());
}

需要xml文件配置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 控制反转, 让 bean1 被 Spring 容器管理 -->
    <bean id="bean1" class="com.dreams.a02.A02.Bean1"/>

    <!-- 控制反转, 让 bean2 被 Spring 容器管理 -->
    <bean id="bean2" class="com.dreams.a02.A02.Bean2">
        <!-- 依赖注入, 建立与 bean1 的依赖关系 -->
        <property name="bean1" ref="bean1"/>
    </bean>
</beans>

如果xml配置了

<context:annotation-config/>

就不用在xml一个一个Bean的注入了,底层就是加入了后置处理器,可以看到输出了处理器

FileSystemXmlApplicationContext:从文件系统中的 XML 配置文件中加载上下文定义,也适合相对独立的应用程序。

// 基于磁盘路径下 xml 格式的配置文件来创建
private static void testFileSystemXmlApplicationContext() {
    FileSystemXmlApplicationContext context =
            new FileSystemXmlApplicationContext(
                    "src\\main\\resources\\a02.xml");
    for (String name : context.getBeanDefinitionNames()) {
        System.out.println(name);
    }

    System.out.println(context.getBean(Bean2.class).getBean1());
}

AnnotationConfigApplicationContext:通过 Java 注解配置来加载上下文定义,适合基于注解的 Spring 应用程序。非web的springboot使用这种

// 较为经典的容器, 基于 java 注解配置类来创建
private static void testAnnotationConfigApplicationContext() {
    AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(Config.class);

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

    System.out.println(context.getBean(Bean2.class).getBean1());
}

还需要配置类

@Configuration
static class Config {
    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean
    public Bean2 bean2(Bean1 bean1) {
        Bean2 bean2 = new Bean2();
        bean2.setBean1(bean1);
        return bean2;
    }
}

static class Bean1 {
}

static class Bean2 {
    private Bean1 bean1;

    public void setBean1(Bean1 bean1) {
        this.bean1 = bean1;
    }

    public Bean1 getBean1() {
        return bean1;
    }
}

可以看到自动加入了处理器。

AnnotationConfigServletWebServerApplicationContext基于 java 配置类来创建, 用于 web 环境,它继承自 GenericWebApplicationContext,这也是springboot的web底层使用的ApplicationContext

// 较为经典的容器, 基于 java 配置类来创建, 用于 web 环境
private static void testAnnotationConfigServletWebServerApplicationContext() {
    AnnotationConfigServletWebServerApplicationContext context =
            new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    for (String name : context.getBeanDefinitionNames()) {
        System.out.println(name);
    }
}

还要配置:

servletWebServerFactory(): 定义了一个 Servlet Web 服务器工厂的 Bean,并返回了一个 TomcatServletWebServerFactory 的实例。(就是内嵌的tomcat)

dispatcherServlet(): 定义了一个 DispatcherServlet 的 Bean,并返回了一个 DispatcherServlet 的实例。

registrationBean(DispatcherServlet dispatcherServlet): 定义了一个 DispatcherServletRegistrationBean 的 Bean,用于将 DispatcherServlet 注册到根路径(“/”)。

@Configuration
static class WebConfig {
    @Bean
    public ServletWebServerFactory servletWebServerFactory(){
        return new TomcatServletWebServerFactory();
    }
    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }
    @Bean
    public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
        return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
    }
    @Bean("/hello")
    public Controller controller1() {
        return (request, response) -> {
            response.getWriter().print("hello");
            return null;
        };
    }
}

 

5.关联

beanFactory解析xml就会调用XmlBeanDefinitionReader来解析xml

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("读取之前...");
for (String name : beanFactory.getBeanDefinitionNames()) {
    System.out.println(name);
}
System.out.println("读取之后...");
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("a02.xml"));
for (String name : beanFactory.getBeanDefinitionNames()) {
    System.out.println(name);
}

 

6.BeanFactory补充

在 Spring 发展阶段中重要,但目前已经很鸡肋的接口 FactoryBean 的使用要点

  • 它的作用是用制造创建过程较为复杂的产品,如 SqlSessionFactory,但 @Bean 已具备等价功能
  • 使用上较为古怪,一不留神就会用错

被 FactoryBean 创建的产品

  • 会认为创建、依赖注入、Aware 接口回调、前初始化这些都是 FactoryBean 的职责, 这些流程都不会走
  • 唯有后初始化的流程会走, 也就是产品可以被代理增强
  • 单例的产品不会存储于 BeanFactory 的 singletonObjects 成员中, 而是另一个factoryBeanObjectCache 成员中。
  • 按名字去获取时, 拿到的是产品对象, 名字前面加 & 获取的是工厂对象

示例代码: Bean2

package com.dreams.demo43;

import org.springframework.stereotype.Component;

@Component
public class Bean2 {
}

Bean1 注意这里并没有@Component注解,也就是不是配置类

package com.dreams.demo43;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;

public class Bean1 implements BeanFactoryAware {
    private static final Logger log = LoggerFactory.getLogger(Bean1.class);

    private Bean2 bean2;

    @Autowired
    public void setBean2(Bean2 bean2) {
        log.debug("setBean2({})", bean2);
        this.bean2 = bean2;
    }

    public Bean2 getBean2() {
        return bean2;
    }

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

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.debug("setBeanFactory({})", beanFactory);
    }
}

Bean1FactoryBean 将该工厂bean声明为 Spring 容器中的一个组件,并指定了它的名字为 “bean1″。

Bean1FactoryBean 类实现了 FactoryBean<Bean1> 接口,这意味着它是一个工厂bean,负责生产 Bean1 类的实例。

FactoryBean 接口方法实现

  • getObjectType() 方法: 指定了工厂bean 生产的对象类型,在这里是 Bean1.class。这告诉 Spring 在需要自动装配时,应该使用哪种类型。
  • isSingleton() 方法: 指定了由该工厂bean 创建的 Bean1 实例是否是单例。在这里,返回 true 表示 Bean1 是单例的,即 Spring 容器中只有一个 Bean1 的实例。
  • getObject() 方法: 这是工厂bean 的核心方法,用于创建并返回 Bean1 的实例。在这里,简单地创建一个新的 Bean1 对象
package com.dreams.demo43;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

@Component("bean1")
public class Bean1FactoryBean implements FactoryBean<Bean1> {

    private static final Logger log = LoggerFactory.getLogger(Bean1FactoryBean.class);

    // 决定了根据【类型】获取或依赖注入能否成功
    @Override
    public Class<?> getObjectType() {
        return Bean1.class;
    }

    // 决定了 getObject() 方法被调用一次还是多次
    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public Bean1 getObject() throws Exception {
        Bean1 bean1 = new Bean1();
        log.debug("create bean: {}", bean1);
        return bean1;
    }
}

Bean1的后置处理器

package com.dreams.demo43;

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

@Component
public class Bean1PostProcessor implements BeanPostProcessor {

    private static final Logger log = LoggerFactory.getLogger(Bean1PostProcessor.class);

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("bean1") && bean instanceof Bean1) {
            log.debug("before [{}] init", beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("bean1") && bean instanceof Bean1) {
            log.debug("after [{}] init", beanName);
        }
        return bean;
    }
}

main方法

package com.dreams.demo43;

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

@ComponentScan
public class Demo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo.class);

        Bean1 bean1 = (Bean1) context.getBean("bean1");
        Bean1 bean2 = (Bean1) context.getBean("bean1");
        Bean1 bean3 = (Bean1) context.getBean("bean1");
        System.out.println(bean1);
        System.out.println(bean2);
        System.out.println(bean3);

        System.out.println(context.getBean(Bean1.class));

        System.out.println(context.getBean(Bean1FactoryBean.class));
        System.out.println(context.getBean("&bean1"));

        context.close();
    }

}

可以看到按名字去获取时, 拿到的是产品对象, 名字前面加 & 获取的是工厂对象,而且Bean1类是由工厂创建的,Bean1的@Autowired、@PostConstruct、Aware回调都失效了。而Bean后处理器只会走初始化后处理postProcessAfterInitialization,初始化后处理的例子就是代理增强了,也就是代理可以生效。

 

7.参考

黑马程序员:spring

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇