我记得以前有人跟我说,“面试的时候要看spring的源码,要看ioc、aop的源码"那为什么要看这些开源框架的源码呢,其实很多人都是"应急式"的去读,就像读一篇文章一下,用最快的速度把文章从头到尾读一遍,那结果就是当你读完它,你也不清楚它讲了一个什么故事,想表达什么。
一个优秀的架构的源码我认为就好像一本名著一样,你的“文学”水平越高,你就越能读出作者设计的精妙之处。一篇源码在你不同水平的时候,能读出不同的东西,因此,我觉得优秀的框架的源码是经久不衰的,反复读多少次都不嫌多,直到你能设计出预期并驾齐驱甚至超越它的优美的架构。
读源码起初是一件很痛苦的事儿,想赶紧把它像流水账一样的读完;慢慢实力增强后,会感觉到读源码能够不费力气的读通;再假以时日,就能看出这些精妙的设计模式的组合。我有一个朋友,典型的源码痴狂症,他跟我说他第一次看见spring的源码,感觉特别兴奋,读了一宿没睡觉.......好吧,我还有很长的路需要走~
话说多了,我们赶紧入正题:
JFinal的框架我24号的一篇博文写到过,它优秀的地方在精简代码上,那么有两处源码是我觉得是值得我们要好好解析一下,一处是初始化加载—servlet跳转,另一处是DB+ActiveRecord的映射。
那么DB映射相对比较简单,我们这次就先来看看。
首先我们看看代码,还是之前我写过的 dog与cat的故事。
// 采用DB+ActiveRecord模式
ActiveRecordPlugin arp = new ActiveRecordPlugin(c3p0Plugin);
me.add(arp);
// 进行DB映射
arp.addMapping(" animal " , AnimalModel.class );
第一步:为ActiveRecordPlugin的 private IDataSourceProvider dataSourceProvider 赋值。 这三行代码就是加载DB映射的关键,那么我们复习一下,JFinal的DB映射无需配置文件,无需与DB对应的POJO,只需要写一个类,继承Model即可。
那么我们先来看看ActiveRecordPlugin的构造器。
public ActiveRecordPlugin(IDataSourceProvider dataSourceProvider) {
this (DbKit.MAIN_CONFIG_NAME, dataSourceProvider);
}
这里重要的是dataSourceProvider,IDataSourceProvider是一个接口,它的运行时类型是
JFinal 源码分析 [DB+ActiveRecord]
那么,可以看到
this (DbKit.MAIN_CONFIG_NAME, dataSourceProvider);
这段代码又继续读取另一个重载的构造器,然后调用了
public ActiveRecordPlugin(String configName, IDataSourceProvider dataSourceProvider, int transactionLevel) {
if (StrKit.isBlank(configName))
throw new IllegalArgumentException(" configName can not be blank " );
if (dataSourceProvider == null )
throw new IllegalArgumentException(" dataSourceProvider can not be null " );
this .configName = configName.trim();
this .dataSourceProvider = dataSourceProvider;
this .setTransactionLevel(transactionLevel);
}
最重要的就是这行代码: this.dataSourceProvider = dataSourceProvider;
这时,ActiveRecordPlugin的static变量的dataSourceProvider就已经被赋为C3p0Plugin的实例了。
第二步:定义映射用POJO
public class AnimalModel extends Model {...}
这里Model的源码我们一会再看,现在不着急。
然后进行映射
// 进行DB映射
arp.addMapping(" animal " , AnimalModel.class );
这里我们又回到了ActiveRecordPlugin类里,它实际上有两个addMapping方法,只是参数不同。
public ActiveRecordPlugin addMapping(String tableName, String primaryKey, Class> modelClass) {
tableList.add( new Table(tableName, primaryKey, modelClass));
return this ;
}
public ActiveRecordPlugin addMapping(String tableName, Class> modelClass) {
tableList.add( new Table(tableName, modelClass));
return this ;
}
我们看到,第一个方法多了一个参数 String primaryKey,我的代码里用的是第二个方法。这两个方法实际上都调用了tableList.add(Table tbl)方法,我们看看tableList是什么
private List tableList = new ArrayList();
它是ActiveRecordPlugin的一个成员变量,并且是private的,那我们可以猜到,tableList保存了所有的映射关系。(ActiveRecordPlugin真是强大,后面会越来越强大~)。
第三步:创建映射关系
new Table(tableName, primaryKey, modelClass)
new Table(tableName, modelClass)
我们进去看看
public Table(String name, Class> modelClass) {
if (StrKit.isBlank(name))
throw new IllegalArgumentException(" Table name can not be blank. " );
if (modelClass == null )
throw new IllegalArgumentException(" Model class can not be null. " );
this .name = name.trim();
this .modelClass = modelClass;
}
public Table(String name, String primaryKey, Class> modelClass) {
if (StrKit.isBlank(name))
throw new IllegalArgumentException(" Table name can not be blank. " );
if (StrKit.isBlank(primaryKey))
throw new IllegalArgumentException(" Primary key can not be blank. " );
if (modelClass == null )
throw new IllegalArgumentException(" Model class can not be null. " );
this .name = name.trim();
setPrimaryKey(primaryKey.trim()); // this.primaryKey = primaryKey.trim();
this .modelClass = modelClass;
}
这两个方法都是为Table里的成员变量赋值,第二个方法,也就是带primaryKey参数的那个多出一行,我们看看这一行干了什么
setPrimaryKey(primaryKey.trim()); // this.primaryKey = primaryKey.trim();
void setPrimaryKey(String primaryKey) {
String[] keyArr = primaryKey.split(" , " );
if (keyArr.length > 1 ) {
if (StrKit.isBlank(keyArr[0 ]) || StrKit.isBlank(keyArr[1 ]))
throw new IllegalArgumentException(" The composite primary key can not be blank. " );
this .primaryKey = keyArr[0 ].trim();
this .secondaryKey = keyArr[1 ].trim();
}
else {
this .primaryKey = primaryKey;
}
这样的作用就是为Table下的primaryKey 和 secondaryKey赋值。
第四步:加载ActiveRecordPlugin
那么代码好像跟到这里就完事了,怎么回事?是不是跟丢了?
别忘了,ActiveRecordPlugin是在FinalConfig里的configPlugin方法加载的。那么又有谁来加载FinalConfig呢?
PS:(FinalConfig是我自己定义的类)
这儿涉及到初始化的加载了,我简单的讲一下。
public class FinalConfig extends JFinalConfig
整个JFinal的入口是web.xml的一段配置:
jfinal
class>com.jfinal.core.JFinalFilter class>
configClass
com.demo.config.FinalConfig
接着我们看到了关键的累 JFinalFilter,还是点进去看看。
public final class JFinalFilter implements Filter
这个类实现了Filter接口,那就得实现方法init(),doFilter(),destroy()方法。
我们去看init()方法:
public void init(FilterConfig filterConfig) throws ServletException {
createJFinalConfig(filterConfig.getInitParameter( " configClass " ));
if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false )
throw new RuntimeException(" JFinal init error! " );
handler = jfinal.getHandler();
constants = Config.getConstants();
encoding = constants.getEncoding();
jfinalConfig.afterJFinalStart();
String contextPath = filterConfig.getServletContext().getContextPath();
contextPathLength = (contextPath == null || " / " .equals(contextPath) ? 0 : contextPath.length());
}
绕过其他的加载,直接看这行
if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false )
我们看看jfinal的类型是 private static final JFinal jfinal = JFinal.me();
那么我们去JFinal类里看看它的init方法。
boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {
this .servletContext = servletContext;
this .contextPath = servletContext.getContextPath();
initPathUtil();
Config.configJFinal(jfinalConfig); // start plugin and init logger factory in this method
constants = Config.getConstants();
initActionMapping();
initHandler();
initRender();
initOreillyCos();
initI18n();
initTokenManager();
return true ;
看这行,下面这行主要是通过Config来加载暴露给程序员的核心文件,JFinalConfig的子类FinalConfig。
Config.configJFinal(jfinalConfig); // start plugin and init logger factory in this method
再点进去
* Config order: constant, route, plugin, interceptor, handler
*/
tatic void configJFinal(JFinalConfig jfinalConfig) {
jfinalConfig.configConstant(constants); initLoggerFactory();
jfinalConfig.configRoute(routes);
jfinalConfig.configPlugin(plugins); startPlugins(); // very important!!!
jfinalConfig.configInterceptor(interceptors);
jfinalConfig.configHandler(handlers);
这段代码实际上有个地方特别坑!就是
jfinalConfig.configPlugin(plugins); startPlugins(); // very important!!!
这行代码一共做了两件事,第一件事是jfinalConfig.configPlugin(plugins);来加载插件。还记得我们之前写的FinalConfig里的configPlugin(Plugins me) 方法吗?
/* *
* Config plugin
* 配置插件
* JFinal有自己独创的 DB + ActiveRecord模式
* 此处需要导入ActiveRecord插件
*/
@Override
public void configPlugin(Plugins me) {
// 读取db配置文件
loadPropertyFile(" db.properties " );
// 采用c3p0数据源
C3p0Plugin c3p0Plugin = new C3p0Plugin(getProperty(" jdbcUrl " ),getProperty(" user " ), getProperty(" password " ));
me.add(c3p0Plugin);
// 采用DB+ActiveRecord模式
ActiveRecordPlugin arp = new ActiveRecordPlugin(c3p0Plugin);
me.add(arp);
// 进行DB映射
arp.addMapping(" animal " , AnimalModel.class );
}
它实际上就是通过me.add来加载插件,通过Config的 private static final Plugins plugins = new Plugins(); 来装载。 第二件事就是 发现没有,后面的startPlugins()不是注释!是一个方法,这块实在太坑了,恰巧,这就是我们要找到的地方。
这个方法的代码有点长,但因为很重要,我不得不都贴出来。
private static void startPlugins() {
List pluginList = plugins.getPluginList();
if (pluginList != null ) {
for (IPlugin plugin : pluginList) {
try {
// process ActiveRecordPlugin devMode
if (plugin instanceof com.jfinal.plugin.activerecord.ActiveRecordPlugin) {
com.jfinal.plugin.activerecord.ActiveRecordPlugin arp =
(com.jfinal.plugin.activerecord.ActiveRecordPlugin)plugin;
if (arp.getDevMode() == null )
arp.setDevMode(constants.getDevMode());
}
boolean success = plugin.start();
if (!success) {
String message = " Plugin start error: " + plugin.getClass().getName();
log.error(message);
throw new RuntimeException(message);
}
}
catch (Exception e) {
String message =
" Plugin start error: " + plugin.getClass().getName() + " . \n " + e.getMessage();
log.error(message, e);
throw new RuntimeException(message, e);
}
}
}
}
上面这个方法一共有两个地方要注意一下,
for (IPlugin plugin : pluginList) {
上面这行是循环所有的插件,并且启动插件的start()方法。
那么,我们中有一个插件记不记得是ActiveRecordPlugin的实例?那么
boolean success = plugin.start();
这行代码就会执行ActiveRecordPlugin下的start()代码。终于绕回来了!!红军二万五千里长征,为了证明这个调用,我写了多少字....
那么我们看ActiveRecordPlugin下的start()方法吧,实际上这个start()方法是因为实现了IPlugin接口里的start()方法。
public boolean start() {
if (isStarted)
return true ;
if (dataSourceProvider != null )
dataSource = dataSourceProvider.getDataSource();
if (dataSource == null )
throw new RuntimeException(" ActiveRecord start error:
ActiveRecordPlugin need DataSource or DataSourceProvider" );
if (config == null )
config = new Config(configName, dataSource, dialect,
showSql, devMode, transactionLevel, containerFactory, cache);
DbKit.addConfig(config);
boolean succeed = TableBuilder.build(tableList, config);
if (succeed) {
Db.init();
isStarted = true ;
}
return succeed;
}
我们直接看与DB映射有关的代码,首先是取得dataSource,dataSourceProvider这个忘了没,忘了就翻到最前面,第一步讲的。
config = new Config(configName, dataSource, dialect, showSql, devMode, transactionLevel, containerFactory, cache);
这行代码中的dataSource 在插件里配置的C3P0数据源。这里的Config与前面加载FinalConfig的可不是一个啊,千万别看错了,这个是DB的 com.jfinal.plugin.activerecord.Config。
第五步:TableBuilder
来自ActiveRecordPlugin.java
boolean succeed = TableBuilder.build(tableList, config);
static boolean build(List tableList, Config config) {
Table temp = null ;
Connection conn = null ;
try {
conn = config.dataSource.getConnection();
TableMapping tableMapping = TableMapping.me();
for (Table table : tableList) {
temp = table;
doBuild(table, conn, config);
tableMapping.putTable(table);
DbKit.addModelToConfigMapping(table.getModelClass(), config);
}
return true ;
} catch (Exception e) {
if (temp != null )
System.err.println( " Can not create Table object,
maybe the table " + temp.getName() + " is not exists." );
throw new ActiveRecordException(e);
}
finally {
config.close(conn);
}
}
这里循环所有的tableList,对每个Table对象进行建表。那么我们先看看Table是用什么来存储数据库映射关系的,相信大家都能猜到是Map了。
public class Table {
private String name;
private String primaryKey;
private String secondaryKey = null ;
private Map> columnTypeMap; // config.containerFactory.getAttrsMap();
private Class> modelClass;
columnTypeMap是关键字段,暂且记下来。
下面我们还是回到TableBuilder里的doBuild(table, conn, config);方法。
这个才是DB映射的关键,我其实直接讲这一个类就可以的......这个方法代码实在太多了,我贴部分代码做讲解吧。
那么第六步:doBuild详解。
这块有点类,我直接在代码里写注释吧:
@SuppressWarnings(" unchecked " )
private static void doBuild(Table table, Connection conn, Config config) throws SQLException {
// 初始化 Table 里的columnTypeMap字段。
table.setColumnTypeMap(config.containerFactory.getAttrsMap());
// 取得主键,如果取不到的话,默认设置"id"。
// 记不记得最开始的两个同名不同参的方法 addMapping(...),
在这才体现出后续处理的不同。
if (table.getPrimaryKey() == null )
table.setPrimaryKey(config.dialect.getDefaultPrimaryKey());
// 此处如果没有设置方言,则默认 Dialect dialect = new MysqlDialect(); Mysql的方言。
// sql为"select * from `" + tableName + "` where 1 = 2";
String sql = config.dialect.forTableBuilderDoBuild(table.getName());
Statement stm = conn.createStatement();
ResultSet rs = stm.executeQuery(sql);
// 取得个字段的信息
ResultSetMetaData rsmd = rs.getMetaData();
// 匹配映射
for (int i=1 ; i<=rsmd.getColumnCount(); i++) {
String colName = rsmd.getColumnName(i);
String colClassName = rsmd.getColumnClassName(i);
if (" java.lang.String " .equals(colClassName)) {
// varchar, char, enum, set, text, tinytext, mediumtext, longtext
table.setColumnType(colName, String.class );
}
else if (" java.lang.Integer " .equals(colClassName)) {
// int, integer, tinyint, smallint, mediumint
table.setColumnType(colName, Integer.class );
}
else if (" java.lang.Long " .equals(colClassName)) {
// bigint
table.setColumnType(colName, Long.class );
}
// else if ("java.util.Date".equals(colClassName)) {
// java.util.Data can not be returned
// java.sql.Date, java.sql.Time,
java.sql.Timestamp all extends java.util.Data so getDate can return the three types data
// result.addInfo(colName, java.util.Date.class);
// }
else if (" java.sql.Date " .equals(colClassName)) {
// date, year
table.setColumnType(colName, java.sql.Date.class );
}
else if (" java.lang.Double " .equals(colClassName)) {
// real, double
table.setColumnType(colName, Double.class );
}
else if (" java.lang.Float " .equals(colClassName)) {
// float
table.setColumnType(colName, Float.class );
}
else if (" java.lang.Boolean " .equals(colClassName)) {
// bit
table.setColumnType(colName, Boolean.class );
}
else if (" java.sql.Time " .equals(colClassName)) {
// time
table.setColumnType(colName, java.sql.Time.class );
}
else if (" java.sql.Timestamp " .equals(colClassName)) {
// timestamp, datetime
table.setColumnType(colName, java.sql.Timestamp.class );
}
else if (" java.math.BigDecimal " .equals(colClassName)) {
// decimal, numeric
table.setColumnType(colName, java.math.BigDecimal.class );
}
else if (" [B " .equals(colClassName)) {
// binary, varbinary, tinyblob, blob, mediumblob, longblob
// qjd project: print_info.content varbinary(61800);
table.setColumnType(colName, byte [].class );
}
else {
int type = rsmd.getColumnType(i);
if (type == Types.BLOB) {
table.setColumnType(colName, byte [].class );
}
else if (type == Types.CLOB || type == Types.NCLOB) {
table.setColumnType(colName, String. class );
}
else {
table.setColumnType(colName, String. class );
}
// core.TypeConverter
// throw new RuntimeException
(" You've got new type to mapping. Please add code in " + TableBuilder.class .getName()
+ " . The ColumnClassName can't be mapped: " + colClassName);
}
}
rs.close();
stm.close();
}
这里巧妙的运用了 where 1=2的无检索条件结果,通过ResultSetMetaData rsmd = rs.getMetaData(); 导出了DB模型,这招确实漂亮。之前我还冥思苦相,他是怎么做的呢,看着此处源码,茅塞顿开。
接着,把编辑好的Table实例,放到TableMapping的成员变量 Model>, Table> modelToTableMap 里去,TableMapping是单例的。
private final Map>, Table> modelToTableMap=
new HashMap>, Table>();
public void putTable(Table table) {
modelToTableMap.put(table.getModelClass(), table);
}
这样,所有的映射关系就都存在TableMapping的modelToTableMap
tableMapping.putTable(table);
再将modelToConfig都放入DbKit.modelToConfig里。
DbKit.addModelToConfigMapping(table.getModelClass(), config);
第七步,使用
Model里的save方法举例:
/* *
* Save model.
*/
public boolean save() {
Config config = getConfig();
Table table = getTable();
StringBuilder sql = new StringBuilder();
List paras = new ArrayList();
config.dialect.forModelSave(table, attrs, sql, paras);
// if (paras.size() == 0) return false;
// The sql "insert into tableName() values()" works fine, so delete this line
// --------
Connection conn = null ;
PreparedStatement pst = null ;
int result = 0 ;
try {
conn = config.getConnection();
if (config.dialect.isOracle())
pst = conn.prepareStatement(sql.toString(),
new String[]{table.getPrimaryKey()});
else
pst = conn.prepareStatement(sql.toString(),
Statement.RETURN_GENERATED_KEYS);
config.dialect.fillStatement(pst, paras);
result = pst.executeUpdate();
getGeneratedKey(pst, table);
getModifyFlag().clear();
return result >= 1 ;
} catch (Exception e) {
throw new ActiveRecordException(e);
} finally {
config.close(pst, conn);
}
}
Config config = getConfig();
上面这行就是调用DbKit的方法,取得DB配置。
public static Config getConfig(Class modelClass) {
return modelToConfig.get (modelClass);
}
下面这段代码是去单例的TableMapping里取得表的具体信息。
Table table = getTable();
private Table getTable() {
return TableMapping.me().getTable(getClass());
}
转载于:https://www.cnblogs.com/visec479/p/4087021.html
你可能感兴趣的:(设计模式,面试,web.xml)
题解 | #完全数计算#不知道为什么没超时的暴力解法
huaxinjiayou
java
兄弟们,坚持就是胜利啊,找工作从去年秋招就开始找,到五月底才收到第一个offer星环的,然后六月初t咋六月了还有面试啊,有兄弟了解这个部门吗面完了家人们,纯纯kpi啊,上来就是一道题是打印多个字符串的华为接头人话术指南:欲投华为,必看此贴!引流华为招聘提前批【奖】这个夏天,和牛牛一起打卡刷题~Java面试实战项目25届本科找暑期实习的历程飞猪旅行运营岗面经百度视觉算法一面面经感谢牛友们,腾子pcg
从简单到复杂:三种工厂模式的对比与应用
技术拾光者
设计模式 java 设计模式 简单工厂模式 抽象工厂模式 工厂方法模式
在软件设计中,创建型设计模式用于处理对象创建的复杂性。本文将对比三种常见的创建型设计模式:简单工厂模式、工厂方法模式和抽象工厂模式。一,简单工厂模式定义:简单工厂模式(SimpleFactoryPattern)定义了一个工厂类,该类可以根据传入的参数决定创建哪一种产品实例。结构:产品(Product):定义产品的接口。具体产品(ConcreteProduct):实现具体产品。工厂(Factory)
【Java】面试题31:栈的压入,弹出序列
小小核桃
剑指offer java版
~~题目:~~输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列{1,2,3,4,5}是某栈的压栈序列,序列{4,5,3,2,1}是该压栈序列对应的一个弹出序列,但{4,3,5,1,2}就不可能是该栈序列的弹出序列。思路:首先借助一个辅助栈,把输入的第一个序列中的数字依次压入该辅助栈,并按照第二个序列的顺序依次从该栈中弹出数
Java字符串为何是不可变的?
木南曌
Java java
Java中字符串是一个非常常用的数据类型,它不仅在日常编码中频繁使用,也是面试中常见的考点之一。一个经常被讨论的话题是Java中的字符串为何是不可变的。本文将探讨这个问题,并解释其背后的原因。引言在Java中,字符串是通过String类来表示的,这个类有一个很重要的特性,那就是不可变性(Immutability)。这意味着一旦一个字符串对象被创建,它的值就不能被更改。例如,当你试图修改一个字符串时
数据库常见笔试面试题及其解析
yxsr_zxx
数据库 数据库 SqlServer Oracle 笔试 面试
数据库基础(面试常见题)一、数据库基础1.数据抽象:物理抽象、概念抽象、视图级抽象,内模式、模式、外模式2.SQL语言包括数据定义、数据操纵(DataManipulation),数据控制(DataControl)数据定义:CreateTable,AlterTable,DropTable,Craete/DropIndex等数据操纵:Select,insert,update,delete,数据控制:g
【华为OD机试真题 python】输出指定字母在字符串的中的索引【2022 Q4 | 100分】
无痕de泪
华为OD机试真题 python 输出指定字母在字符串的中的索引 字符串 华为od python
前言《华为OD笔试真题python》专栏含华为OD机试真题、华为面试题、牛客网华为专栏真题。如果您正在准备华为的面试,或者华为od的机会,有任何想了解的可以私信我进行交流。我会尽可能的给一些建议,和帮您解答!PS:文中答案仅供参考,不能照抄哦■题目描述【输出指定字母在字符串的中的索引】给定一个字符串,把字符串按照大写在前小写在后排序,输出排好后的第K个字母在原来字符串的索引。相同字母输出第一个出现
大数据真实面试题---SQL
The博宇
大数据面试题——SQL 大数据 mysql sql 数据库 big data
视频号数据分析组外包招聘笔试题时间限时45分钟完成。题目根据3张表表结构,写出具体求解的SQL代码(搞笑品类定义:视频分类或者视频创建者分类为“搞笑”)1、表创建语句:createtablet_user_video_action_d(dsint,user_idstring,video_idstring,action_typeint,`timestamp`bigint)rowformatdelimi
职场内卷,太累了!7个方法让你“破局”(收藏)
张涔汐
文|张涔汐上上个周,涔汐做了一场直播,关于个人如何快速成长的话题。涔汐实力宠粉,把直播干货分享给大家了。话不多说,上干货。我们先思考一个问题,为什么有些人在职场三年五载,还是老样子呢?因为他们总是指望别人能教他,就如同《天道》的王庙村村民,没事儿往教堂跑,指望上帝保佑发财,期待高人指点脱贫致富一个道理。如果你想要在短短时间内,获得成长。01摒弃指望别人教你成长的观念,保持成长思维很多人面试的过程中
面试常见题之Spring Cloud
拾光编程
java面试 面试 spring cloud 职场和发展
在Java软件工程师的面试中,关于SpringCloud的题目旨在考察候选人对微服务架构的理解、SpringCloud各组件的掌握程度、以及如何在实际项目中应用这些技术来构建可扩展、可靠和高效的服务。本文将概括性地列出20个关于SpringCloud的面试题目,并为每个题目提供一个简要的回答框架或关键点,以便你根据需要进行扩展。1.SpringCloud是什么?它解决了什么问题?回答框架:Spri
分享欲的重要性
玺晴
不管是亲情、友情还是爱情,我觉得分享欲还是蛮重要的,当你开始对一个人逐渐没有了分享的欲望,其实也意味着你们的关系正在逐渐疏远,或许是已经疏远了。毕业后呢,W和N是我联系最多的两个人,我们几乎每天都会聊天,聊的内容并不是什么大事,都是一些琐碎的事情,或是一些情绪化的东西。例如,W去面试的时候被放鸽子了,她提前到了那家公司,却被通知已经不招人了,于是呢,她向我吐槽这家公司,为了面试她化了妆,坐了差不多
面试题24. 反转链表
阿星啊阿星
反转链表题目描述定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点示例:输入:1->2->3->4->5->NULL输出:5->4->3->2->1->NULL提示:0<=节点个数<=5000转载来源:力扣(LeetCode)题目分析1→2→3→null初始化时h为1,now为2,h的next设置成null,有:null←1(h) 2(now)→3现在将保存一下now的next
一文搞懂应用架构的3个核心概念
公众号-架构师汤师爷
后端 架构设计 Java SaaS
如果你是一名业务开发,你可能要说,我整天就是做CRUD(增删改查),哪里需要了解什么应用架构设计?经常有人说,程序员35岁之后很容易陷入瓶颈,被行业淘汰,我觉得原因其实就在此。有些朋友在写代码的时候,可能没有太多考虑非功能性的需求、扩展性,只是完成功能,觉得能用就好。做事情的时候,也没有长远的规划,只是把眼前的事情做好就满足了。我面试过很多大龄候选人,他们的简历长达十几页,项目经历有几十个。然而,
当前最流行的架构设计模式
turingbooks
《微服务设计(第2版)》最可贵的地方在于,不光具备理论性与系统性,更为注重实践性与可操作性。全书勾勒出一幅从宏观到细节,再到组织落地的微服务架构整体实施蓝图。无论是对关注微服务领域的工程师与架构师,还是对寻求架构升级的管理者与决策者来说,本书都可以作为指导手册。——沈剑,快狗打车CTO《微服务设计(第2版)》萨姆·纽曼|著钟健鑫张沙沙智伟|译软件开发大神MartinFowler如此推荐本书:“微服
互联网 Java 工程师面试题(Java 面试题四)
苹果酱0567
面试题汇总与解析 java 中间件 开发语言 spring boot 后端
下面列出这份Java面试问题列表包含的主题多线程,并发及线程基础数据类型转换的基本原则垃圾回收(GC)Java集合框架数组字符串GOF设计模式SOLID抽象类与接口Java基础,如equals和hashcode泛型与枚举JavaIO与NIO常用网络协议Java中的数据结构和算法正则表达式JVM底层Java最佳实JDBCDate,Time与CalendarJava处理XMLJUnit编程现在是时候给
《Android进阶之光》— Android 书籍
王睿丶
Android 永无止境 《Android进阶之光》 Android书籍 Android phoenix 移动开发
文章目录第1章Android新特性1第2章MaterialDesign48第3章View体系与自定义View87第4章多线程编程165第5章网络编程与网络框架204第6章设计模式271第7章事件总线308第8章函数响应式编程333第9章注解与依赖注入框架382第10章应用架构设计422第11章系统架构与MediaPlayer框架460出版年:2017-7简介:《Android进阶之光》是一本And
面试题篇: 跨域问题如何处理(Java和Nginx处理方式)
guicai_guojia
java nginx 开发语言
1.服务器端解决方案最常见的解决方案是在服务器端配置CORS头。服务器需要在响应中添加适当的Access-Control-Allow-头来允许跨域请求。1.1NGINX配置在NGINX配置中,你可以通过add_header指令来设置CORS头。配置示例:server{ listen80; server_nameapi.example.com; location/{ proxy_pass
android进阶之光!Android面试必备的集合源码详解,系列篇
程序员Sunbu
程序员 Android
前言面试:如果不准备充分的面试,完全是浪费时间,更是对自己的不负责。文末会给大家分享下我整理的Android面试专题及答案其中大部分都是大企业面试常问的面试题,可以对照这查漏补缺,当然了,这里所列的肯定不可能覆盖全部方式,不过对大家找工作肯定是有帮助!本月飞机到达上海,到今天第6天了,四家大公司华为,小米,映客,抖音,还有二家中小型公司。有几家已经面了几轮,下周还要面,挂了几家,不过目前已经选择了
面试失败的自我反省
无用之大
星期一早上,我主动用邮箱联系上周五面试的HR姐姐。过了半个小时,收到HR姐姐的回复,说我:不好意思没有通过面试的信息,具体原因不清楚。但同时,她给予我一些宝贵的面试经验:今后建议你可以从这些方面改进:1.多跟别人交流自己的想法,提高自己在表达时的音量,语速,语言的运用,可以让让别人感觉到你的自信。2.面试中多与对方进行表情,眼神的互动。3.回答问题时,先思考1-2秒,整理好自己的思路再回答,说话要
2022-03-01
薇薇林
为什么企业人力资源管理师证书没有用?人力资源管理,俗称HR,是个人就能做吗?在普罗大众的刻板印象里,HR人事就是招招人,发发工资,五点准时下班,闲得很,技术门槛为零。但人力资源管理是包含了六大模块的,说人话就是会定KPI、会做培训体系,上能在招聘宣传中娓娓道来,下能狠心开除问题员工,对内可甜,对外可盐。优秀的大公司都把人力看做第一资源。在汇丰银行,HR是有一票否决权的,即使你通过部门主管的面试、部
面试前夕
枯皮囊
明天面试,今天我们一行人坐火车去目的地宾馆,晚上吃了美美的一餐,价格稍贵,但是很值得,味美量多,挺喜欢的。希望明天运气爆棚,面试顺顺利利,并且抽到一个我擅长的题目。各位亲们,晚安喽,愉快的一天。我走的很慢,但从不后退。图片发自App
【面试】嵌入式面试常见题目收藏(超总结)_嵌入式面试题目及答案
2401_83641314
程序员 嵌入式
16.死锁的4个必要条件答:1、互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。2、占有且等待:一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。3、不可抢占:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。4、循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至
浅谈大模型 SFT 的实践落地:十问十答
大模型与自然语言处理
NLP与大模型 人工智能 大数据 深度学习 多模态 大模型 SFT
节前,我们星球组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂朋友、参加社招和校招面试的同学.针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。汇总合集:《大模型面试宝典》(2024版)发布!今天给大家带来一篇大模型SFT的实践落地经验总结SFT现在往往被称为“低端”工作,但它与业务紧密相连。相较于难以实施且多数公司没资源训
Ihandy Unity开发 面试题 2024
z2014z
面试 职场和发展
1.当i>10时,调用test是否会出现死锁?原因是什么?voidtest(inti){lock(this){if(i>10){i--;test(i);}}}2.有一个表有n条记录,每条记录有两个字段,weight和id,写出程序保证id出现的概率与权重相同3.从1到n,一共有多少个14.二叉树的层次遍历5.给定两个链表,将对应数值相加6.检查两棵树是否相同
多线程相关面试题(2024大厂高频面试题系列)
小橘子831
后端面试 java 面试 后端
1、聊一下并行和并发有什么区别?并发是同一时间应对多件事情的能力,多个线程轮流使用一个或多个CPU并行是同一时间动手做多件事情的能力,4核CPU同时执行4个线程2、说一下线程和进程的区别?进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间3、如果在java中创建线程有哪些方式?在java中一共有四种常见的创建方式,
Java多线程相关面试题整理
长河落日袁同学
不积跬步无以至千里 java 笔记 多线程 锁 面试
目录1.什么是线程和进程?线程与进程有什么区别?那什么是上下文切换?进程间怎么通信?什么是用户线程和守护线程?2.并行和并发的区别?3.创建线程的几种方式?Runnable接口和Callable接口的区别?run()方法和start()有什么区别?4.Java线程状态和方法?描述线程的生命周期?一个线程两次调用start()方法会出现什么情况?sleep()和wait()方法的区别是什么?5.并发
说来惭愧,今年我已经被辞退16次了
吾聊职场
一个人能走多远,能到怎样的高度,才华、运气、背景……说起来好像有很多决定因素,但有时可能只取决于下面这一点。文丨王耳朵先生(lD:huangezishiba)你见过跳槽最多的人,是什么样的?我见过的是:半年,16次。前几天,去朋友的公司谈事情,刚巧他们在招聘,我也坐下来听了一会儿。正在面试的,是位大学已毕业好几年的女生。她的自我介绍里,有句话引起所有人的注意:今年才过去一半,她已经跳槽和被辞退16
MyBatis 方法重载的陷阱及解决方案
molashaonian
mybatis 方法重载 异常 方法名相同
在使用MyBatis进行开发时,尤其是使用注解模式(如@Select、@Insert等)时,开发者常常会遇到这样一个问题:为什么我的方法重载不能正常工作?即使在Java中允许方法名相同但参数不同的重载,MyBatis在处理注解的SQL方法时却并不支持这种方式。这篇文章将深入探讨MyBatis的这个特性及如何规避相关的坑。问题背景在标准的Java开发中,方法重载是一种常见的设计模式。方法重载允许我们
Java面试题--JVM大厂篇之深入解析JVM中的Serial GC:工作原理与代际区别
青云交
Java大厂面试题 Java虚拟机(JVM)专栏 Java技术栈 Serial GC工作原理 年轻代垃圾回收Minor GC 老年代垃圾回收 MajorGC FullGC 年轻代和老年代的区别 SerialGC垃圾收集器 单线程垃圾收集器
目录引言:正文:一、SerialGC工作原理年轻代垃圾回收(MinorGC):老年代垃圾回收(MajorGC或FullGC):二、年轻代和老年代的区别年轻代(YoungGeneration):老年代(OldGeneration):结束语:引言:Java虚拟机(JVM)作为Java程序的运行环境,其性能和稳定性在很大程度上依赖于垃圾收集器(GC)的效率。SerialGC是JVM中最古老也是最简单的一
golang面试题 001
Jay_hj11
golang面试 Golang golang 后端 数据结构 开发语言 面试
001gochannelclose后读的问题golangchannel关闭后,其中剩余的数据,是可以继续读取的。请看下面的测试例子。创建一个带有缓冲的channel,向channel中发送数据,然后关闭channel,最后,从channel中读取数据,输出结果。packagemainimport"fmt"//gochannelclose后读的问题funcmain(){ch:=make(chanst
前端基础面试题·第三篇——JavaScript(其二)
DT——
前端面试 javascript 面试
1.深浅拷贝1.浅拷贝浅拷贝会创建一个新的对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝就是改引用类型的地址。//常见的浅拷贝1.Object.assign({},obj)//对象浅拷贝assign⽅法可以⽤于处理数组,不过会把数组视为对象,⽐如这⾥会把⽬标数组视为是属性为0、1、2的对象,所以源数组的0、1属性的值覆盖了⽬标对
HQL之投影查询
归来朝歌
HQL Hibernate 查询语句 投影查询
在HQL查询中,常常面临这样一个场景,对于多表查询,是要将一个表的对象查出来还是要只需要每个表中的几个字段,最后放在一起显示?
针对上面的场景,如果需要将一个对象查出来:
HQL语句写“from 对象”即可
Session session = HibernateUtil.openSession();
Spring整合redis
bylijinnan
redis
pom.xml
<dependencies>
<!-- Spring Data - Redis Library -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redi
org.hibernate.NonUniqueResultException: query did not return a unique result: 2
0624chenhong
Hibernate
参考:http://blog.csdn.net/qingfeilee/article/details/7052736
org.hibernate.NonUniqueResultException: query did not return a unique result: 2
在项目中出现了org.hiber
android动画效果
不懂事的小屁孩
android动画
前几天弄alertdialog和popupwindow的时候,用到了android的动画效果,今天专门研究了一下关于android的动画效果,列出来,方便以后使用。
Android 平台提供了两类动画。 一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转、平移、放缩和渐变)。
第二类就是 Frame动画,即顺序的播放事先做好的图像,与gif图片原理类似。
js delete 删除机理以及它的内存泄露问题的解决方案
换个号韩国红果果
JavaScript
delete删除属性时只是解除了属性与对象的绑定,故当属性值为一个对象时,删除时会造成内存泄露 (其实还未删除)
举例:
var person={name:{firstname:'bob'}}
var p=person.name
delete person.name
p.firstname -->'bob'
// 依然可以访问p.firstname,存在内存泄露
Oracle将零干预分析加入网络即服务计划
蓝儿唯美
oracle
由Oracle通信技术部门主导的演示项目并没有在本月较早前法国南斯举行的行业集团TM论坛大会中获得嘉奖。但是,Oracle通信官员解雇致力于打造一个支持零干预分配和编制功能的网络即服务(NaaS)平台,帮助企业以更灵活和更适合云的方式实现通信服务提供商(CSP)的连接产品。这个Oracle主导的项目属于TM Forum Live!活动上展示的Catalyst计划的19个项目之一。Catalyst计
spring学习——springmvc(二)
a-john
springMVC
Spring MVC提供了非常方便的文件上传功能。
1,配置Spring支持文件上传:
DispatcherServlet本身并不知道如何处理multipart的表单数据,需要一个multipart解析器把POST请求的multipart数据中抽取出来,这样DispatcherServlet就能将其传递给我们的控制器了。为了在Spring中注册multipart解析器,需要声明一个实现了Mul
POJ-2828-Buy Tickets
aijuans
ACM_POJ
POJ-2828-Buy Tickets
http://poj.org/problem?id=2828
线段树,逆序插入
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>using namespace std;#define N 200010struct
Java Ant build.xml详解
asia007
build.xml
1,什么是antant是构建工具2,什么是构建概念到处可查到,形象来说,你要把代码从某个地方拿来,编译,再拷贝到某个地方去等等操作,当然不仅与此,但是主要用来干这个3,ant的好处跨平台 --因为ant是使用java实现的,所以它跨平台使用简单--与ant的兄弟make比起来语法清晰--同样是和make相比功能强大--ant能做的事情很多,可能你用了很久,你仍然不知道它能有
android按钮监听器的四种技术
百合不是茶
android xml配置 监听器 实现接口
android开发中经常会用到各种各样的监听器,android监听器的写法与java又有不同的地方;
1,activity中使用内部类实现接口 ,创建内部类实例 使用add方法 与java类似
创建监听器的实例
myLis lis = new myLis();
使用add方法给按钮添加监听器
软件架构师不等同于资深程序员
bijian1013
程序员 架构师 架构设计
本文的作者Armel Nene是ETAPIX Global公司的首席架构师,他居住在伦敦,他参与过的开源项目包括 Apache Lucene,,Apache Nutch, Liferay 和 Pentaho等。
如今很多的公司
TeamForge Wiki Syntax & CollabNet User Information Center
sunjing
TeamForge How do Attachement Anchor Wiki Syntax
the CollabNet user information center http://help.collab.net/
How do I create a new Wiki page?
A CollabNet TeamForge project can have any number of Wiki pages. All Wiki pages are linked, and
【Redis四】Redis数据类型
bit1129
redis
概述
Redis是一个高性能的数据结构服务器,称之为数据结构服务器的原因是,它提供了丰富的数据类型以满足不同的应用场景,本文对Redis的数据类型以及对这些类型可能的操作进行总结。
Redis常用的数据类型包括string、set、list、hash以及sorted set.Redis本身是K/V系统,这里的数据类型指的是value的类型,而不是key的类型,key的类型只有一种即string
SSH2整合-附源码
白糖_
eclipse spring tomcat Hibernate Google
今天用eclipse终于整合出了struts2+hibernate+spring框架。
我创建的是tomcat项目,需要有tomcat插件。导入项目以后,鼠标右键选择属性,然后再找到“tomcat”项,勾选一下“Is a tomcat project”即可。具体方法见源码里的jsp图片,sql也在源码里。
补充1:项目中部分jar包不是最新版的,可能导
[转]开源项目代码的学习方法
braveCS
学习方法
转自:
http://blog.sina.com.cn/s/blog_693458530100lk5m.html
http://www.cnblogs.com/west-link/archive/2011/06/07/2074466.html
1)阅读features。以此来搞清楚该项目有哪些特性2)思考。想想如果自己来做有这些features的项目该如何构架3)下载并安装d
编程之美-子数组的最大和(二维)
bylijinnan
编程之美
package beautyOfCoding;
import java.util.Arrays;
import java.util.Random;
public class MaxSubArraySum2 {
/**
* 编程之美 子数组之和的最大值(二维)
*/
private static final int ROW = 5;
private stat
读书笔记-3
chengxuyuancsdn
jquery笔记 resultMap配置 ibatis一对多配置
1、resultMap配置
2、ibatis一对多配置
3、jquery笔记
1、resultMap配置
当<select resultMap="topic_data">
<resultMap id="topic_data">必须一一对应。
(1)<resultMap class="tblTopic&q
[物理与天文]物理学新进展
comsci
如果我们必须获得某种地球上没有的矿石,才能够进行某些能量输出装置的设计和建造,而要获得这种矿石,又必须首先进行深空探测,而要进行深空探测,又必须获得这种能量输出装置,这个矛盾的循环,会导致地球联盟在与宇宙文明建立关系的时候,陷入困境
怎么办呢?
 
Oracle 11g新特性:Automatic Diagnostic Repository
daizj
oracle ADR
Oracle Database 11g的FDI(Fault Diagnosability Infrastructure)是自动化诊断方面的又一增强。
FDI的一个关键组件是自动诊断库(Automatic Diagnostic Repository-ADR)。
在oracle 11g中,alert文件的信息是以xml的文件格式存在的,另外提供了普通文本格式的alert文件。
这两份log文
简单排序:选择排序
dieslrae
选择排序
public void selectSort(int[] array){
int select;
for(int i=0;i<array.length;i++){
select = i;
for(int k=i+1;k<array.leng
C语言学习六指针的经典程序,互换两个数字
dcj3sjt126com
c
示例程序,swap_1和swap_2都是错误的,推理从1开始推到2,2没完成,推到3就完成了
# include <stdio.h>
void swap_1(int, int);
void swap_2(int *, int *);
void swap_3(int *, int *);
int main(void)
{
int a = 3;
int b =
php 5.4中php-fpm 的重启、终止操作命令
dcj3sjt126com
PHP
php 5.4中php-fpm 的重启、终止操作命令:
查看php运行目录命令:which php/usr/bin/php
查看php-fpm进程数:ps aux | grep -c php-fpm
查看运行内存/usr/bin/php -i|grep mem
重启php-fpm/etc/init.d/php-fpm restart
在phpinfo()输出内容可以看到php
线程同步工具类
shuizhaosi888
同步工具类
同步工具类包括信号量(Semaphore)、栅栏(barrier)、闭锁(CountDownLatch)
闭锁(CountDownLatch)
public class RunMain {
public long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
fin
bleeding edge是什么意思
haojinghua
DI
不止一次,看到很多讲技术的文章里面出现过这个词语。今天终于弄懂了——通过朋友给的浏览软件,上了wiki。
我再一次感到,没有辞典能像WiKi一样,给出这样体贴人心、一清二楚的解释了。为了表达我对WiKi的喜爱,只好在此一一中英对照,给大家上次课。
In computer science, bleeding edge is a term that
c中实现utf8和gbk的互转
jimmee
c iconv utf8&gbk编码
#include <iconv.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
int code_c
大型分布式网站架构设计与实践
lilin530
应用服务器 搜索引擎
1.大型网站软件系统的特点?
a.高并发,大流量。
b.高可用。
c.海量数据。
d.用户分布广泛,网络情况复杂。
e.安全环境恶劣。
f.需求快速变更,发布频繁。
g.渐进式发展。
2.大型网站架构演化发展历程?
a.初始阶段的网站架构。
应用程序,数据库,文件等所有的资源都在一台服务器上。
b.应用服务器和数据服务器分离。
c.使用缓存改善网站性能。
d.使用应用
在代码中获取Android theme中的attr属性值
OliveExcel
android theme
Android的Theme是由各种attr组合而成, 每个attr对应了这个属性的一个引用, 这个引用又可以是各种东西.
在某些情况下, 我们需要获取非自定义的主题下某个属性的内容 (比如拿到系统默认的配色colorAccent), 操作方式举例一则:
int defaultColor = 0xFF000000;
int[] attrsArray = { andorid.r.
基于Zookeeper的分布式共享锁
roadrunners
zookeeper 分布式 共享锁
首先,说说我们的场景,订单服务是做成集群的,当两个以上结点同时收到一个相同订单的创建指令,这时并发就产生了,系统就会重复创建订单。等等......场景。这时,分布式共享锁就闪亮登场了。
共享锁在同一个进程中是很容易实现的,但在跨进程或者在不同Server之间就不好实现了。Zookeeper就很容易实现。具体的实现原理官网和其它网站也有翻译,这里就不在赘述了。
官
两个容易被忽略的MySQL知识
tomcat_oracle
mysql
1、varchar(5)可以存储多少个汉字,多少个字母数字? 相信有好多人应该跟我一样,对这个已经很熟悉了,根据经验我们能很快的做出决定,比如说用varchar(200)去存储url等等,但是,即使你用了很多次也很熟悉了,也有可能对上面的问题做出错误的回答。 这个问题我查了好多资料,有的人说是可以存储5个字符,2.5个汉字(每个汉字占用两个字节的话),有的人说这个要区分版本,5.0
zoj 3827 Information Entropy(水题)
阿尔萨斯
format
题目链接:zoj 3827 Information Entropy
题目大意:三种底,计算和。
解题思路:调用库函数就可以直接算了,不过要注意Pi = 0的时候,不过它题目里居然也讲了。。。limp→0+plogb(p)=0,因为p是logp的高阶。
#include <cstdio>
#include <cstring>
#include <cmath&