前言

几个月前阅读spring文档时做的笔记,记录了以写我认为重要的内容.

IOC container

IOC(Inverse of Control) 控制反转,也称为DI(Dependency Inject)依赖注入

一个对象定义它所需要的依赖,IOC容器会在对象创建时将这些依赖注入.

举个例子 如果没有IOC,对于依赖我们可能这样处理

public class A{private B b;public A(){this.b=new B();}
}
复制代码

现实情况会更复杂,B可能还有自己的依赖,如果B的实例化过程发生变化,所有对B有依赖的对象都要做修改.更麻烦的是,如果A,B有相同的依赖,或者形成的循环依赖(有一部分循环依赖IOC也无法处理,但是有很大一部分通过IOC根本不会形成循环依赖),依赖关系会更无法处理.

有了IOC就会变成这样

public class A{@Autowiredprivate B b;
}
复制代码

A只需要声明它需要的依赖,IOC容器会在A实例化时自动注入相关的依赖.如果B发生变化,A无需改动.这里体现了IOC的一个重要作用解耦

org.springframework.beans 和 org.springframework.context

上面两个包是IOC容器的基础,BeanFactor提供了配置和管理功能,ApplicationContext在BeanFactory的基础上进一步封装,添加了一些企业级特性,更易集成使用

什么是bean

在Spring中,构成应用骨架的且由IOC Container进行管理的那些Object称为bean.一个bean就是一个由IOC Container进行实例化,装配且管理的Object

Container 概述

ApplicationContext

org.springframework.context.ApplicationContext 接口代表container,负责bean的实例化,配置和装配.

container通过读取configuration metadata获取实例化,配置和装配bean的说明,configuration metadata由xml文件,注解及java代码表示.

Spring 提供了两个开箱即用的ApplicationContext实现,  ClassPathXmlApplicationContextFileSystemXmlApplicationContext

Configuration metadata

configuration metadata 是用户(你)以开发者的角度提供给Spring的数据,告诉Spring应该怎样去处理bean.

主要有三种类型的metadata

  • XML-Based
  • Annotation-Based
  • Java-Based @Configuration @Bean @Import @DependsOn

对于XML,顶级标签下的每个元素表示一个bean definition

对于注解,含有@Configuration的类中含有@Bean的方法都是一个bean definition

使用import元素来整合多个配置文件(相对路径),Spring官方不推荐"../service.xml"这可能导致依赖

<beans><import resource="services.xml"/><import resource="resources/messageSource.xml"/><import resource="/resources/themeSource.xml"/><bean id="bean1" class="..."/><bean id="bean2" class="..."/>
</beans>
复制代码

基于groovy的bean definition,看起来更加方便

beans {dataSource(BasicDataSource) {driverClassName = "org.hsqldb.jdbcDriver"url = "jdbc:hsqldb:mem:grailsDB"username = "sa"password = ""settings = [mynew:"setting"]}sessionFactory(SessionFactory) {dataSource = dataSource}myService(MyService) {nestedBean = { AnotherBean bean ->dataSource = dataSource}}
}
复制代码

容器的启动

基于groovy的启动

ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
复制代码

GeneralApplicationContext使用最灵活,也最麻烦,需要关注细节,如下

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
复制代码

beanDefinition

如果没有提供命名,默认以下面这种方式命名:bean names start with a lowercase letter, and are camel-cased from then on

class Instantiating beans
name Naming beans
scope Bean scopes
constructor arguments Dependency Injection
properties Dependency Injection
autowiring mode Autowiring collaborators
lazy-initialization mode Lazy-initialized beans
initialization method Initialization callbacks
destruction method Destruction callbacks

基于xml的实例化

  • 通过构造器实例化
<bean id="exampleBean" class="examples.ExampleBean"/><bean name="anotherExample" class="examples.ExampleBeanTwo"/>
复制代码
  • 通过静态工厂方法实例化
<bean id="clientService"class="examples.ClientService"factory-method="createInstance"/>
复制代码
  • 通过工厂方法实例化
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator"><!-- inject any dependencies required by this locator bean -->
</bean><!-- the bean to be created via the factory bean -->
<bean id="clientService"factory-bean="serviceLocator"factory-method="createClientServiceInstance"/>
复制代码

DI

  • 构造器注入
public class SimpleMovieLister {// the SimpleMovieLister has a dependency on a MovieFinderprivate MovieFinder movieFinder;// a constructor so that the Spring container can inject a MovieFinderpublic SimpleMovieLister(MovieFinder movieFinder) {this.movieFinder = movieFinder;}// business logic that actually uses the injected MovieFinder is omitted...
}
复制代码
  • 构造器注入不同类型的多个参数
<beans><bean id="foo" class="x.y.Foo"><constructor-arg ref="bar"/><constructor-arg ref="baz"/></bean><bean id="bar" class="x.y.Bar"/><bean id="baz" class="x.y.Baz"/>
</beans>
复制代码
  • 构造器注入多个不同简单类型
<bean id="exampleBean" class="examples.ExampleBean"><constructor-arg type="int" value="7500000"/><constructor-arg type="java.lang.String" value="42"/>
</bean>
复制代码
  • 构造器注入时指定顺序
<bean id="exampleBean" class="examples.ExampleBean"><constructor-arg index="0" value="7500000"/><constructor-arg index="1" value="42"/>
</bean>
复制代码
  • 构造器注入时指定名称(需要在编译时开启debug)
<bean id="exampleBean" class="examples.ExampleBean"><constructor-arg name="years" value="7500000"/><constructor-arg name="ultimateAnswer" value="42"/>
</bean>
复制代码
  • 作为前者的替代,使用java annotation
package examples;public class ExampleBean {// Fields omitted@ConstructorProperties({"years", "ultimateAnswer"})public ExampleBean(int years, String ultimateAnswer) {this.years = years;this.ultimateAnswer = ultimateAnswer;}
}
复制代码

构造器注入vs Setter注入

  • 构造器注入强制依赖不为空,并且可以保证bean在装配完成后不会再发生变化.
  • 原始的setter注入用来注入那些非必须的依赖,@Required注入可以使其变为强制依赖
  • 按照目前情况,setter注入更为实用,尤其是@Autowired注解

依赖解析过程

  1. ApplicationContext通过读取metadata完成创建和初始化
  2. 对于所有bean,它的依赖都是通过属性,构造器参数,静态工厂方法参数等,当bean真正被创建时(对于 scope为singleton的bean来说,立刻创建),这些依赖被注入
  3. 每个属性和构造器参数都是一个要被设置的值或是容器中其他bean的引用
  4. 原始类型的属性被会自动转化,例如将String转为int,long double等等.

使用setter注入取代构造器注入解决循环依赖问题??

ApplicationContext 默认使用 pre-instantiate初始化singleton的bean,也可以更改为lazy-initialize,如果一个bean到运行很长时间后才被请求到,这时候去创建时,很可能出现异常.Spring采用以启动时间和内存换去运行安全的策略

idref标签

用以传递值(而非ref),主要目的是提供部署时检查,通常用在

*A common place (at least in versions earlier than Spring 2.0) where the element brings value is in the configuration of AOP interceptors in a ProxyFactoryBean bean definition. Using  elements when you specify the interceptor names prevents you from misspelling an interceptor id. *

<bean id="theTargetBean" class="..."/><bean id="theClientBean" class="..."><property name="targetName"><idref bean="theTargetBean"/></property>
</bean>
复制代码

作用和下面相同

<bean id="theTargetBean" class="..." /><bean id="client" class="..."><property name="targetName" value="theTargetBean"/>
</bean>
复制代码

idref的local标签在beans xsd 4.0已被废弃

容器支持

<bean id="moreComplexObject" class="example.ComplexObject"><!-- results in a setAdminEmails(java.util.Properties) call --><property name="adminEmails"><props><prop key="administrator">administrator@example.org</prop><prop key="support">support@example.org</prop><prop key="development">development@example.org</prop></props></property><!-- results in a setSomeList(java.util.List) call --><property name="someList"><list><value>a list element followed by a reference</value><ref bean="myDataSource" /></list></property><!-- results in a setSomeMap(java.util.Map) call --><property name="someMap"><map><entry key="an entry" value="just some string"/><entry key ="a ref" value-ref="myDataSource"/></map></property><!-- results in a setSomeSet(java.util.Set) call --><property name="someSet"><set><value>just some string</value><ref bean="myDataSource" /></set></property>
</bean>
复制代码

map或set中的值可以为以下几种

bean | ref | idref | list | set | map | props | value | null
复制代码

继承时集合的融合和覆盖


<beans><bean id="parent" abstract="true" class="example.ComplexObject"><property name="adminEmails"><props><prop key="administrator">administrator@example.com</prop><prop key="support">support@example.com</prop></props></property></bean><bean id="child" parent="parent"><property name="adminEmails"><!-- the merge is specified on the child collection definition --><props merge="true"><prop key="sales">sales@example.com</prop><prop key="support">support@example.co.uk</prop></props></property></bean>
<beans>
复制代码

对于list有一点特殊,他有顺序的概念,父类优于子类

对集合中空字符串和null的处理

<bean class="ExampleBean"><property name="email" value=""/>
</bean>exampleBean.setEmail("");
复制代码
<bean class="ExampleBean"><property name="email"><null/></property>
</bean>exampleBean.setEmail(null);
复制代码

复合属性要求路径上的对象不能为空, fred,bob都不能为空,否则nullpointer异常

<bean id="foo" class="foo.Bar"><property name="fred.bob.sammy" value="123" />
</bean>
复制代码

depends on

对于关联较小且由实例化顺序要求的两个bean,通过 depends on实现强制指定顺序处理


<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
复制代码

对于多个依赖


<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao"><property name="manager" ref="manager" />
</bean><bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
复制代码

对于singleton的bean,depends on 还有控制 destory 顺序的作用

lazy-initializad

在第一次请求到时才初始化,不推荐,ApplicationContext的默认策略是pre-instantiation


<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.foo.AnotherBean"/>
复制代码

控制全局的初始化策略


<beans default-lazy-init="true"><!-- no beans will be pre-instantiated... -->
</beans>
复制代码

基于 xml的 autowired

不推荐 限制太多

方法注入

场景, 一个singleton的bean需要依赖于一个prototype的bean,或相反

有三个解决方案

  1. 通过实现 ApplicationContextAware 接口获取ApplicationContext,再用来实现自定义功能

// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;public class CommandManager implements ApplicationContextAware {private ApplicationContext applicationContext;public Object process(Map commandState) {// grab a new instance of the appropriate CommandCommand command = createCommand();// set the state on the (hopefully brand new) Command instancecommand.setState(commandState);return command.execute();}protected Command createCommand() {// notice the Spring API dependency!return this.applicationContext.getBean("command", Command.class);}public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}
复制代码
  1. 通过 lookup的xml形式(通过cglib生成子类完成)
package fiona.apple;// no more Spring imports!public abstract class CommandManager {public Object process(Object commandState) {// grab a new instance of the appropriate Command interfaceCommand command = createCommand();// set the state on the (hopefully brand new) Command instancecommand.setState(commandState);return command.execute();}// okay... but where is the implementation of this method?protected abstract Command createCommand();
}<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype"><!-- inject dependencies here as required -->
</bean><!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager"><lookup-method name="createCommand" bean="myCommand"/>
</bean>
复制代码
  1. 通过lookup的注解形式,最方便,推荐

public abstract class CommandManager {public Object process(Object commandState) {Command command = createCommand();command.setState(commandState);return command.execute();}@Lookup("myCommand")protected abstract Command createCommand();
}public abstract class CommandManager {public Object process(Object commandState) {MyCommand command = createCommand();command.setState(commandState);return command.execute();}@Lookupprotected abstract MyCommand createCommand();
}
复制代码

注意

  1. 该类不能是final,被覆盖的方法也不能是final
  2. 无法于工厂方法一起工作,对于@Configuration的@Bean也是无法工作的
  3. 单元测试需要自己去stub一个子类

Scope

singleton

每个容器中只会有一个singleton的bean,Spring的singleton定义为per container and per bean

prototype

每次向容器请求时都会生成一个新的Object,与其它scope的类型最大的区别就是它的回收需要客户端自己去处理(可以通过beanPostProcessor处理)

long-live bean中注入short-live bean时可以使用以下方法


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- an HTTP Session-scoped bean exposed as a proxy --><bean id="userPreferences" class="com.foo.UserPreferences" scope="session"><!-- instructs the container to proxy the surrounding bean --><aop:scoped-proxy/></bean><!-- a singleton-scoped bean injected with a proxy to the above bean --><bean id="userService" class="com.foo.SimpleUserService"><!-- a reference to the proxied userPreferences bean --><property name="userPreferences" ref="userPreferences"/></bean>
</beans>
复制代码

上面的例子中,userPreferences有apo:scoped-proxy/,这说明他是一个被代理的对象,每次userService调用到它时,实际是调用了代理,代理通过自身逻辑获取对应的session-scoped的bean,再执行真实对象的操作(默认使用的CGLIB)

自定义Scope

实现 org.springframework.beans.factory.config.Scope 实现自定义scope

Spring 拓展点

BeanPostProcessor

If you want to implement some custom logic after the Spring container finishes instantiating, configuring, and initializing a bean, you can plug in one or more BeanPostProcessor implementations.

对spring中解决bean的依赖并且初始化后的操作,可以使用BeanPostProcessor

  1. 在Spring调用afterPropertiesSet或initMethod之前, beanPostProcessor会被调用
  2. 在Spring调用initMethod之后,BeanPostProcessor会被调用

ApplicationContext会检查BeanDefinition,对实现了BeanPostProcessor的bean,将其注册为BeanPostProcessor

作为BeanPostProcessor的bean是不会被BeanPostProcessor处理的

BeanFactoryPostProcessor

  1. PropertyPlaceholderConfigurer 实现参数值替换

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations" value="classpath:com/foo/jdbc.properties"/>
    </bean><bean id="dataSource" destroy-method="close"class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/>
    </bean>
    复制代码
  2. PropertyPlaceholderConfigurer 实现类名替换


<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations"><value>classpath:com/foo/strategy.properties</value></property><property name="properties"><value>custom.strategy.class=com.foo.DefaultStrategy</value></property>
</bean><bean id="serviceStrategy" class="${custom.strategy.class}"/>
复制代码
  1. PropertyOverrideConfigurer 覆盖默认值

<context:property-override location="classpath:override.properties"/>
复制代码

FactoryBean 获取制造bean的bean

FactoryBean有三个方法

  1. Object getObject()
  2. boolean isSingleton()
  3. boolean isSingleton()

ApplicationContext.getBean("$beanName")可以获取FactoryBean

lifeCycle

afterPropertiesSet和PostConstruct

在Spring容器完成必要的依赖注入后,会调用该方法完成初始化,此时所有的BeanPostProcessor还未执行


<!--两个作用相同,约定的力量-->
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/><bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
复制代码

//这两个作用也相同,但是更推荐前者
public class ExampleBean {public void init() {// do some initialization work}
}public class AnotherExampleBean implements InitializingBean {public void afterPropertiesSet() {// do some initialization work}
}复制代码

destroy和@PreDestroy

在Spring容器销毁前会调用该方法


<!--两者作用相同-->
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/><bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
复制代码

public class ExampleBean {public void cleanup() {// do some destruction work (like releasing pooled connections)}
}public class AnotherExampleBean implements DisposableBean {public void destroy() {// do some destruction work (like releasing pooled connections)}
}
复制代码

*实现了java.lang.AutoCloseable or java.io.Closeable的bean,可以让Spring自动检测它的close/shutdown方法 *

如果同时定义个多个 lifecycle,会按照 annotation interface xml的顺序执行,并且同名的只执行一次

Startup and shutdown callbacks

stop不能保证


public interface Lifecycle {void start();void stop();boolean isRunning();
}public interface LifecycleProcessor extends Lifecycle {void onRefresh();void onClose();
}
复制代码

Context refresh :所有bean都被实例化和初始化后

@Autowired@Inject@Resource, and @Value annotations are handled by Spring BeanPostProcessorimplementations

@Autowired和@Resource的区别

@Resourceannotation, which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process. @Autowired has rather different semantics: After selecting candidate beans by type, the specified String qualifier value will be considered within those type-selected candidates only, e.g. matching an "account" qualifier against beans marked with the same qualifier label.

CustomAutowireConfigurer

也是beanPostProcessor,用来处理自定义注解(如@Qualify)

@Autowired的匹配过程

先匹配名字的customerPreferenceDao的bean,再匹配类型是CustomerPreferenceDao的bean


public class MovieRecommender {@Resourceprivate CustomerPreferenceDao customerPreferenceDao;@Resourceprivate ApplicationContext context;public MovieRecommender() {}// ...
}
复制代码

CommonAnnotationBeanPostProcessor

处理@Resource和与生命周期相关的bean

@ComponentScan(basePackages = "org.example")

完全的java config,与之对应的xml为


<context:component-scan base-package="org.example"/>复制代码

the AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor are both included implicitly when you use the component-scan element.

使用component-scan后会自动包含 AutowiredAnnotationBeanPostProcessor 和CommonAnnotationBeanPostProcessor

在package-scan的基础上包含或去处class


@Configuration
@ComponentScan(basePackages = "org.example",includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),excludeFilters = @Filter(Repository.class))
public class AppConfig {...
}
复制代码

#{ expression }

实现BeanNameGenerator实现自定义bean命名


@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {...
}<beans><context:component-scan base-package="org.example"name-generator="org.example.MyNameGenerator" />
</beans>
复制代码

实现 ScopeMetadataResolver接口实现自定义Scope解析


@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {...
}<beans><context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver"/>
</beans>
复制代码

@Profile

使用Profile时尽量不要使用重载,可能导致十分奇怪的问题

激活profile有一下方式


AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();-Dspring.profiles.active="profile1,profile2"
复制代码

设置默认的profile


setDefaultProfiles()
spring.profiles.default
复制代码

spring官方文档阅读笔记相关推荐

  1. Qt官方文档阅读笔记-对官方Star Delegate Example实例的解析

    对应的博文为: 目录 Star Delegate Example StarDelegate Class Definition StarDelegate Class Implementation Sta ...

  2. Qt官方文档阅读笔记-QStyledItemDelegate Class描述

    对应的原文为: 笔记如下: 简单描述: QStyledItemDelegate提供了展示和编辑item的功能,让这两种功能更有个性化.QStyledItemDelegate是所有Item View的默 ...

  3. Spring官方文档阅读(二)之Bean的简单理解与使用

    1.3.Bean简介 Spring IoC容器管理一个或多个bean,这些bean是使用我们提供给容器的配置元数据创建的(例如,以XML<bean//>定义的形式 ),在容器本身内,这些b ...

  4. Flume官方文档阅读笔记及实际操作

    欢迎来到Apache Flume Flume是一个分布式的,高可靠的,高可用的,高性能的海量日志数据采集.聚合和传输的系统.它是基于数据流的简单的灵活的架构.它具有高鲁棒性并且有着可调节的可靠的故障恢 ...

  5. Ti 官方文档阅读笔记

    文章目录 参考资料 Optimizing TI mmWave Radar Configurations for FCC Certification Programming Chirp Paramete ...

  6. Javassist 官方文档 随手笔记

    Javassist 官方文档 随手笔记 Javassist.CtClass Class search path Introspection and customization \$0, \$1, \$ ...

  7. ZooKeeper官方文档学习笔记03-程序员指南03

    我的每一篇这种正经文章,都是我努力克制玩心的成果,我可太难了,和自己做斗争. ZooKeeper官方文档学习笔记04-程序员指南03 绑定 Java绑定 客户端配置参数 C绑定 陷阱: 常见问题及故障 ...

  8. Spring官方文档中文翻译

    准备做个Spring官方文档全翻译专栏以下是大目录, 本翻译是基于Spring5 Core Technologies

  9. Spring 官方文档彩蛋

    Spring 官方文档彩蛋 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句 ...

最新文章

  1. jvm六:主动使用(1.new一个对象, 2.反射)
  2. c#根据年份和月份获得本月最后一天
  3. HTML多选框滚动条,《HTM单选.doc
  4. [Leedcode][JAVA][第820题][字典树][Set]
  5. Spark Scalaa 几个常用的示例
  6. 如何重构千行“又臭又长”的类,IntelliJ IDEA 几分钟搞定!
  7. 微软提高 Microsoft 365 的漏洞奖励
  8. deeplearning.ai——TensorFlow指南
  9. linux 文件系统的简单操作
  10. Taobao 的 Linux 内核开源贡献
  11. eclipse php使用方法,Eclipse PHPEclipse 配置的具体步骤
  12. 【24】基于java的宠物医院管理系统
  13. 小米miui adb删除自带软件
  14. 两独立样本非参数检验的Mann-whitneyU检验
  15. 升级macOS Catalina 后辅助功能空白无法添加的问题
  16. python用谷歌内核制作浏览器_用cef Python打造自己的浏览器
  17. L1-040. 最佳情侣身高差
  18. ORA-04031: 无法分配 3840 字节的共享内存 (“shared pool“,“unknown object“,“sga heap(1,0)“,“kglsim object batch“)
  19. ASCII2ChineseSheet
  20. mt4 谐波_【干货分享】比肩波浪理论,被誉为最难技术形态的谐波形态是什么?...

热门文章

  1. 巨量模型时代,浪潮不做旁观者:2457亿参数,打造全球最大中文预训练模型
  2. SAP MM 关于采购组设计的思考
  3. 手机黑产为啥没支付宝的份?官方回应:犯罪分子无法突破人脸识别
  4. 22 款神经网络的设计和可视化工具
  5. 将深度学习技术应用到实际项目
  6. AI芯片进入新阶段 哪种企业能胜出?
  7. latex中的\label标签的作用
  8. Science:细胞如何测量自身的大小?答案是:DNA含量
  9. 谋局科技创新:两院院士大会释放重要信号
  10. 邬贺铨:工业互联网的网络技术