一对一
实例
D:\shen\java\webdevelop\spring\segmentfault-lessons-master\spring-boot\lesson-8\spring-boot-lesson-8\src\main\java\com\segmentfault\springbootlesson8\entity\Customer.java
数据库 SHOW CREATE TABLE customers;
一对一,一对多
D:\shen\java\webdevelop\spring\segmentfault-lessons-master\spring-boot\lesson-8\spring-boot-lesson-8\src\main\java\com\segmentfault\springbootlesson8\entity\Customer.java和Store.java
多对多
总结:
通过MBG可以生成:模型对象,操作模型对象的Java接口,模型对象sql语句的Mappers xml
通过JPA的注解生成数据表、外键关联(参考的Entity定义:D:\shen\java\webdevelop\spring\segmentfault-lessons-master\spring-boot\lesson-8\spring-boot-lesson-8\src\main\java\com\segmentfault\springbootlesson8\entity\)
实现mysql数据库主键id自增
在实体的主键上添加注解 @GeneratedValue(strategy=GenerationType.IDENTITY)
@Entity
@Table(name = "OPERATION_LOG")
public class test implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "operation_id")
private Long operationid;
}
实体类继承
java开发相关文档
通过rest服务操作:(E:\shen\spring\Java 微服务实践 - Spring Boot 系列\08Java 微服务实践 - Spring Boot 系列(八)JPA - mercyblitz - SegmentFault)
EnableTransactionManagement.proxyTargetClass的2种方式:
false: cglib
true: standard Java interface-based proxies
EventListener
CrudRepository
分页
设置proxyTargetClass = true
相关文档:
Spring Data JPA
spring-boot-reference
JSR
ddl-auto:create----每次运行该程序,没有表格会新建表格,表内有数据会清空
ddl-auto:create-drop----每次程序结束的时候会清空表
ddl-auto:update----每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新
ddl-auto:validate----运行程序会校验数据与数据库的字段类型是否相同,不同会报错
CacheManager
Guava
Redis
RedisAutoConfiguration
可见性
一致性
Lock-free
乐观锁
悲观锁
public class Swticher {
private volatile boolean on;
public boolean isOn() {
return on;
}
public void setOn(boolean on) {
this.on = on;
}
}
当有一些列操作时,即使是ConcurrentMap,也是会混乱
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
private volatile Set<String> cacheNames = Collections.emptySet();
// Early cache initialization on startup
@Override
public void afterPropertiesSet() {
initializeCaches();
}
/**
* Initialize the static configuration of caches.
* <p>Triggered on startup through {@link #afterPropertiesSet()};
* can also be called to re-initialize at runtime.
* @since 4.2.2
* @see #loadCaches()
*/
public void initializeCaches() {
Collection<? extends Cache> caches = loadCaches();
synchronized (this.cacheMap) {
this.cacheNames = Collections.emptySet();
this.cacheMap.clear();
Set<String> cacheNames = new LinkedHashSet<>(caches.size());
for (Cache cache : caches) {
String name = cache.getName();
this.cacheMap.put(name, decorateCache(cache));
cacheNames.add(name);
}
this.cacheNames = Collections.unmodifiableSet(cacheNames);
}
}
.....
}
commons.apache.org
Components | Description | Latest Version | Released |
---|---|---|---|
BCEL | Byte Code Engineering Library - analyze, create, and manipulate Java class files | 6.3.1 | 2019-03-24 |
BeanUtils | Easy-to-use wrappers around the Java reflection and introspection APIs. | 1.9.4 | 2019-08-13 |
BSF | Bean Scripting Framework - interface to scripting languages, including JSR-223 | 3.1 | 2010-06-24 |
Chain | Chain of Responsibility pattern implemention. | 1.2 | 2008-06-02 |
CLI | Command Line arguments parser. | 1.4 | 2017-03-09 |
Codec | General encoding/decoding algorithms (for example phonetic, base64, URL). | 1.13 | 2019-07-23 |
Collections | Extends or augments the Java Collections Framework. | 4.4 | 2019-07-08 |
Compress | Defines an API for working with tar, zip and bzip2 files. | 1.19 | 2019-08-27 |
Configuration | Reading of configuration/preferences files in various formats. | 2.5 | 2019-05-27 |
Crypto | A cryptographic library optimized with AES-NI wrapping Openssl or JCE algorithm implementations. | 1.0.0 | 2016-07-22 |
CSV | Component for reading and writing comma separated value files. | 1.7 | 2019-06-05 |
Daemon | Alternative invocation mechanism for unix-daemon-like java code. | 1.0.15 | 2013-04-03 |
DBCP | Database connection pooling services. | 2.7.0 | 2019-08-07 |
DbUtils | JDBC helper library. | 1.7 | 2017-07-20 |
Digester | XML-to-Java-object mapping utility. | 3.2 | 2011-12-13 |
Library for sending e-mail from Java. | 1.5 | 2017-08-01 | |
Exec | API for dealing with external process execution and environment management in Java. | 1.3 | 2014-11-06 |
FileUpload | File upload capability for your servlets and web applications. | 1.4 | 2019-01-16 |
Functor | A functor is a function that can be manipulated as an object, or an object representing a single, generic function. | 1.0 | 2011-??-?? |
Geometry | Space and coordinates. | 1.0 | 2018-??-?? |
Imaging (previously called Sanselan) | A pure-Java image library. | 1.0-alpha1 | 2019-05-02 |
IO | Collection of I/O utilities. | 2.6 | 2017-10-15 |
JCI | Java Compiler Interface | 1.1 | 2013-10-14 |
JCS | Java Caching System | 2.2,1 | 2018-08-23 |
Jelly | XML based scripting and processing engine. | 1.0.1 | 2017-09-27 |
Jexl | Expression language which extends the Expression Language of the JSTL. | 3.1 | 2017-04-14 |
JXPath | Utilities for manipulating Java Beans using the XPath syntax. | 1.3 | 2008-08-14 |
Lang | Provides extra functionality for classes in java.lang. | 3.9 | 2019-04-15 |
Logging | Wrapper around a variety of logging API implementations. | 1.2 | 2014-07-11 |
Math | Lightweight, self-contained mathematics and statistics components. | 3.5 | 2015-04-17 |
Net | Collection of network utilities and protocol implementations. | 3.6 | 2017-02-15 |
Numbers | Number types (complex, quaternion, fraction) and utilities (arrays, combinatorics). | 1.0 | 2017-??-?? |
OGNL | An Object-Graph Navigation Language | 4.0 | 2013-??-?? |
Pool | Generic object pooling component. | 2.7.0 | 2019-07-29 |
Proxy | Library for creating dynamic proxies. | 1.0 | 2008-02-28 |
RDF | Common implementation of RDF 1.1 that could be implemented by systems on the JVM. | 0.3.0-incubating | 2016-11-15 |
RNG | Implementations of random numbers generators. | 1.2 | 2018-12-12 |
SCXML | An implementation of the State Chart XML specification aimed at creating and maintaining a Java SCXML engine. It is capable of executing a state machine defined using a SCXML document, and abstracts out the environment interfaces. |
0.9 | 2008-12-01 |
Statistics | Statistics. | 0.1 | ????-??-?? |
Text | Apache Commons Text is a library focused on algorithms working on strings. | 1.8 | 2019-09-02 |
Validator | Framework to define validators and validation rules in an xml file. | 1.6 | 2017-02-21 |
VFS | Virtual File System component for treating files, FTP, SMB, ZIP and such like as a single logical file system. | 2.4.1 | 2019-08-15 |
Weaver | Provides an easy way to enhance (weave) compiled bytecode. | 2.0 | 2018-09-07 |
技术的广度和深度
文档:
JSR-303
spring framework reference 5
scanBasePackages指定spring扫描的包范围
localhost:8080/beans权限控制
根据ManagementServerProperties在properties中进行设置
security.enabled
注意相关项目依赖的版本
org.springframework.security.web.csrf.CsrfTokenRepository
框架版本兼容性:
源码兼容:编译打包时,即可发现
运行时兼容:ClassNotFound, ClassDefNotFound
装配原理:
配置文件的数据是如何被装备的:
加载application.yml的配置属性
跟踪源码的技巧,追踪load方法的调用链,找到相关的listener
spring.factories
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer
# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
默认spring对processor的排序(按文件中的定义顺序)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
通过实现自定义的ApplicationListener的Order接口设置加载顺序(优先级越高,越优先加载配置)
package com.segmentfault.springbootlesson18.context;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import java.util.HashMap;
import java.util.Map;
/**
* 自定义 Spring Boot {@link ApplicationListener}
*
* @author <a href="mailto:[email protected]">Mercy</a>
* @see ApplicationEnvironmentPreparedEvent
* @since 2017.09.09
*/
public class CustomizedSpringBootApplicationListener implements
ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment env = event.getEnvironment();
MutablePropertySources mutablePropertySources = env.getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("server.port", 5678);
source.put("spring.profiles.include", "sss");
PropertySource propertySource = new MapPropertySource("from-application-listener", source);
mutablePropertySources.addFirst(propertySource);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
相同getOrder()的优先级,看classpath加载顺序,一般是项目内优先于外部jar包
spring boot启动后,通过/env查看加载顺序
{
"profiles": [
"sss",
"prod"
],
"server.ports": {
"local.server.port": 5678
},
"java-code": {
"server.port": 1234,
"spring.profiles.include": "abc"
},
"from-application-listener": {
"server.port": 1234,
"spring.profiles.include": "abc"
},
"servletContextInitParams": {},
"systemProperties": {
"java.runtime.name": "Java(TM) SE Runtime Environment",
"sun.boot.library.path": "D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\bin",
"java.vm.version": "25.144-b01",
"java.vm.vendor": "Oracle Corporation",
"java.vendor.url": "http://java.oracle.com/",
"path.separator": ";",
"java.vm.name": "Java HotSpot(TM) 64-Bit Server VM",
"file.encoding.pkg": "sun.io",
"user.country": "CN",
"user.script": "",
"sun.java.launcher": "SUN_STANDARD",
"sun.os.patch.level": "",
"PID": "27284",
"java.vm.specification.name": "Java Virtual Machine Specification",
"user.dir": "d:\\shen\\java\\webdevelop\\spring\\segmentfault-lessons-master\\spring-boot\\lesson-18",
"java.runtime.version": "1.8.0_144-b01",
"java.awt.graphicsenv": "sun.awt.Win32GraphicsEnvironment",
"org.jboss.logging.provider": "slf4j",
"java.endorsed.dirs": "D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\lib\\endorsed",
"os.arch": "amd64",
"java.io.tmpdir": "C:\\Users\\shen\\AppData\\Local\\Temp\\",
"line.separator": "\r\n",
"java.vm.specification.vendor": "Oracle Corporation",
"user.variant": "",
"os.name": "Windows 10",
"sun.jnu.encoding": "GBK",
"spring.beaninfo.ignore": "true",
"java.library.path": "D:\\Program Files\\Java\\jdk1.8.0_144\\bin;C:\\WINDOWS\\Sun\\Java\\bin;C:\\WINDOWS\\system32;C:\\WINDOWS;D:\\Python37-32;C:\\ProgramData\\Oracle\\Java\\javapath;C:\\Windows\\system32;C:\\Windows;D:\\Program Files\\Java\\jdk1.8.0_144\\bin;D:\\software\\tcping-src\\;D:\\ProgramApp\\nvm;D:\\software\\Sublime Text Build 3176 x64\\;D:\\software\\mysql-5.7.24-winx64;D:\\software\\mysql-5.7.24-winx64\\bin\\;D:\\Go\\bin;D:\\HashiCorp\\Vagrant\\bin;d:\\nvm;d:\\Program Files\\nodejs;D:\\Program Files\\nodejs\\;D:\\software\\apache-maven-3.6.3\\bin;D:\\Python37-32\\Scripts\\;D:\\Python37-32\\;D:\\shen\\work\\自动化测试\\driver;D:\\Program Files (x86)\\Subversion\\bin;D:\\Program Files\\Fiddler;D:\\Program Files\\Microsoft VS Code\\bin;D:\\ProgramApp\\nvm;C:\\Program Files\\nodejs;C:\\Users\\shen\\AppData\\Local\\GitHubDesktop\\bin;C:\\Users\\shen\\AppData\\Local\\Microsoft\\WindowsApps;D:\\shen\\work\\source\\go_workspaces;D:\\shen\\work\\source\\dns;\\bin;D:\\Gobin;C:\\Program Files\\nodejs\\node_modules\\stylelint\\bin;d:\\nvm;d:\\Program Files\\nodejs;C:\\Users\\shen\\AppData\\Roaming\\npm;;.",
"java.specification.name": "Java Platform API Specification",
"java.class.version": "52.0",
"sun.management.compiler": "HotSpot 64-Bit Tiered Compilers",
"os.version": "10.0",
"user.home": "C:\\Users\\shen",
"catalina.useNaming": "false",
"user.timezone": "Asia/Shanghai",
"java.awt.printerjob": "sun.awt.windows.WPrinterJob",
"file.encoding": "UTF-8",
"java.specification.version": "1.8",
"catalina.home": "C:\\Users\\shen\\AppData\\Local\\Temp\\tomcat.6263626499854450717.5678",
"java.class.path": "C:\\Users\\shen\\AppData\\Local\\Temp\\cp_1uxf6q9mccwo87to9wl43ve4q.jar",
"user.name": "shen",
"java.vm.specification.version": "1.8",
"sun.java.command": "com.segmentfault.springbootlesson18.SpringBootLesson18Application",
"java.home": "D:\\Program Files\\Java\\jdk1.8.0_144\\jre",
"sun.arch.data.model": "64",
"user.language": "zh",
"java.specification.vendor": "Oracle Corporation",
"awt.toolkit": "sun.awt.windows.WToolkit",
"java.vm.info": "mixed mode",
"java.version": "1.8.0_144",
"java.ext.dirs": "D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\lib\\ext;C:\\WINDOWS\\Sun\\Java\\lib\\ext",
"sun.boot.class.path": "D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\lib\\resources.jar;D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\lib\\rt.jar;D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\lib\\sunrsasign.jar;D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\lib\\jsse.jar;D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\lib\\jce.jar;D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\lib\\charsets.jar;D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\lib\\jfr.jar;D:\\Program Files\\Java\\jdk1.8.0_144\\jre\\classes",
"java.awt.headless": "true",
"java.vendor": "Oracle Corporation",
"sun.stderr.encoding": "cp65001",
"catalina.base": "C:\\Users\\shen\\AppData\\Local\\Temp\\tomcat.6263626499854450717.5678",
"file.separator": "\\",
"java.vendor.url.bug": "http://bugreport.sun.com/bugreport/",
"sun.io.unicode.encoding": "UnicodeLittle",
"sun.cpu.endian": "little",
"sun.stdout.encoding": "cp65001",
"sun.desktop": "windows",
"sun.cpu.isalist": "amd64"
},
"systemEnvironment": {
"USERDOMAIN_ROAMINGPROFILE": "DESKTOP-NR5O5ND",
"NVM_SYMLINK": "d:\\Program Files\\nodejs",
"PROCESSOR_LEVEL": "6",
"SESSIONNAME": "Console",
"ALLUSERSPROFILE": "C:\\ProgramData",
"PROCESSOR_ARCHITECTURE": "AMD64",
"PSModulePath": "C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules",
"python3": "D:\\Program Files\\Python36",
"SystemDrive": "C:",
"=ExitCode": "00000000",
"MOZ_PLUGIN_PATH": "D:\\Program Files\\FoxitReader\\Foxit Reader\\plugins\\",
"COLORTERM": "truecolor",
"USERNAME": "shen",
"TERM_PROGRAM_VERSION": "1.42.1",
"ProgramFiles(x86)": "C:\\Program Files (x86)",
"CMDER_ROOT": "D:\\Program Files\\cmder",
"PATHEXT": ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC",
"DriverData": "C:\\Windows\\System32\\Drivers\\DriverData",
"nvm": "D:\\360安全浏览器下载\\nvm-noinstall",
"GOPATH": "D:\\shen\\work\\source\\go_workspaces;D:\\shen\\work\\source\\dns;",
"ProgramData": "C:\\ProgramData",
"ProgramW6432": "C:\\Program Files",
"HOMEPATH": "\\Users\\shen",
"MYSQL_HOME": "D:\\software\\mysql-5.7.24-winx64",
"PROCESSOR_IDENTIFIER": "Intel64 Family 6 Model 142 Stepping 9, GenuineIntel",
"M2_HOME": "D:\\software\\apache-maven-3.6.3",
"ProgramFiles": "C:\\Program Files",
"PUBLIC": "C:\\Users\\Public",
"windir": "C:\\WINDOWS",
"cmder": "D:\\Program Files\\cmder",
"LOCALAPPDATA": "C:\\Users\\shen\\AppData\\Local",
"APR_ICONV_PATH": "D:\\Program Files (x86)\\Subversion\\iconv",
"USERDOMAIN": "DESKTOP-NR5O5ND",
"LOGONSERVER": "\\\\DESKTOP-NR5O5ND",
"WORKON_HOME": "D:\\envs\\",
"JAVA_HOME": "D:\\Program Files\\Java\\jdk1.8.0_144",
"PROMPT": "$P$G",
"LANG": "zh_CN.UTF-8",
"OneDrive": "C:\\Users\\shen\\OneDrive",
"APPDATA": "C:\\Users\\shen\\AppData\\Roaming",
"VBOX_MSI_INSTALL_PATH": "D:\\Program Files\\Oracle\\VirtualBox\\",
"CommonProgramFiles": "C:\\Program Files\\Common Files",
"Path": "D:\\Python37-32;C:\\ProgramData\\Oracle\\Java\\javapath;C:\\Windows\\system32;C:\\Windows;D:\\Program Files\\Java\\jdk1.8.0_144\\bin;D:\\software\\tcping-src\\;D:\\ProgramApp\\nvm;D:\\software\\Sublime Text Build 3176 x64\\;D:\\software\\mysql-5.7.24-winx64;D:\\software\\mysql-5.7.24-winx64\\bin\\;D:\\Go\\bin;D:\\HashiCorp\\Vagrant\\bin;d:\\nvm;d:\\Program Files\\nodejs;D:\\Program Files\\nodejs\\;D:\\software\\apache-maven-3.6.3\\bin;D:\\Python37-32\\Scripts\\;D:\\Python37-32\\;D:\\shen\\work\\自动化测试\\driver;D:\\Program Files (x86)\\Subversion\\bin;D:\\Program Files\\Fiddler;D:\\Program Files\\Microsoft VS Code\\bin;D:\\ProgramApp\\nvm;C:\\Program Files\\nodejs;C:\\Users\\shen\\AppData\\Local\\GitHubDesktop\\bin;C:\\Users\\shen\\AppData\\Local\\Microsoft\\WindowsApps;D:\\shen\\work\\source\\go_workspaces;D:\\shen\\work\\source\\dns;\\bin;D:\\Gobin;C:\\Program Files\\nodejs\\node_modules\\stylelint\\bin;d:\\nvm;d:\\Program Files\\nodejs;C:\\Users\\shen\\AppData\\Roaming\\npm;",
"OS": "Windows_NT",
"TERM_PROGRAM": "vscode",
"COMPUTERNAME": "DESKTOP-NR5O5ND",
"NVM_HOME": "d:\\nvm",
"PROCESSOR_REVISION": "8e09",
"CommonProgramW6432": "C:\\Program Files\\Common Files",
"GOROOT": "D:\\Go",
"ComSpec": "C:\\WINDOWS\\system32\\cmd.exe",
"url": "jdbc:mysql://127.0.0.1:3306/springtest?serverTimezone=UTC",
"=D:": "d:\\shen\\java\\webdevelop\\spring\\segmentfault-lessons-master\\spring-boot\\lesson-18",
"SystemRoot": "C:\\WINDOWS",
"TEMP": "C:\\Users\\shen\\AppData\\Local\\Temp",
"HOMEDRIVE": "C:",
"USERPROFILE": "C:\\Users\\shen",
"TMP": "C:\\Users\\shen\\AppData\\Local\\Temp",
"CommonProgramFiles(x86)": "C:\\Program Files (x86)\\Common Files",
"NUMBER_OF_PROCESSORS": "4"
},
"applicationConfig: [classpath:/application-prod.properties]": {
"server.port": 1234
},
"applicationConfig: [classpath:/application.properties]": {
"server.port": 1234,
"book.name": "Spring Boot æ·±å¥å®è·µ",
"book.isbn": "abc-def",
"person.id": "9",
"management.security.enabled": "false",
"person.age": "18"
}
}
查看具体某个属性
{
"url": "jdbc:mysql://127.0.0.1:3306/springtest?serverTimezone=UTC"
}
Themyleaf
前缀+controller api return value+后缀
技巧:
WebMvcConfigurerAdapter适配器前面的WebMvcConfigurer一般会是一个接口
文档:spring-security-reference
服务端安全
spring security使用了配置模式,XXXConfigurer(WebMvcConfigurer)
idea构建项目的方式:
在pom中设置<scope>import</scope>导入版本
(在springboot文档中搜索关键字<scope>import可以找到配置项内容)
如何排除同名类的不同源包:参考视频
maven分析tree
多排除几次直到maven tree没有该包为止
如何记住类
用前先看下官方文档,了解下原理,大致的实现,文档先看下overview,了解大致框架
记住英文名称,根据命名模式, 比较多个同类框架,结合原理,搞定一个,举一反三。
java logging
spring-boot-reference
LoggingSystem
当多个日志框架都存在时,spring会选择logback
org.springframework.boot.context.logging.LoggingApplicationListener
ConfigurationProperties的2种配置方式:
方式一:
Bean的class定义:
public class City {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //实现映射数据库主键id 自增
@TableId(type = IdType.AUTO) // insert with pk increment by db
private long id;
@Column(length = 20)
@NotNull
private String city;
...
}
配置文件中@Bean
@ConditionalOnWebApplication
public class ApplicationAutoConfiguration {
@Bean("primaryCity")
@ConfigurationProperties(prefix = "city")
public City city() {
return new City();
}
...
}
方式二:
ConfigurationProperties注解class:
@ConfigurationProperties(prefix = "city")
public class City {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //实现映射数据库主键id 自增
@TableId(type = IdType.AUTO) // insert with pk increment by db
private long id;
@Column(length = 20)
@NotNull
private String city;
...
}
配置文件中@EnableConfigurationProperties
@ConditionalOnWebApplication
@EnableConfigurationProperties(City.class)
public class ApplicationAutoConfiguration {
@Bean("primaryCity")
public City city() {
return new City();
}
...
}
spring boot : bean定义兼容spring-bean的方式
调试参数的值:
idea调试:
src/main/resources/logback.xml
<configuration>
<property name="logPath" value="./log" />
<!-- ConsoleAppender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<!-- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%5p] [%thread] %highlight(%c:%L) : %m %n</pattern>
</encoder>
</appender>
<!-- FileAppender -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${logPath}/app.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%5p] [%thread] %c:%L : %m %n</pattern>
</encoder>
</appender>
<!-- RollingFileAppender -->
<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/app_rolling.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history capped at 3GB total size -->
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%5p] [%thread] %c:%L : %m %n</pattern>
</encoder>
</appender>
<!-- 按包范围设置打印日志的等级 -->
<logger name="ik.starriver.log" level="DEBUG"/>
<logger name="org.springframework.web.servlet.DispatcherServlet" level="DEBUG" />
<logger name="org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor" level="DEBUG" />
<logger name="org.hibernate.SQL" level="DEBUG" />
<!-- 设置根日志的等级 -->
<root level="INFO">
<appender-ref ref="STDOUT"/> <!-- 设置appender -->
<appender-ref ref="FILE" />
<appender-ref ref="ROLLING_FILE" />
</root>
</configuration>
查找application.properties的技巧:
已mangement为例
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
beans:
enabled: true
通过快捷键Find in Path
注意观察命名方式,和java类名与包名的反转规则如出一辙。
当需要使用某个类的时候,可以extend该类的接口实现类或者Adapter
XXXAdapter的语义就是要适配XXX接口但是不实现任何方法
定义testListener通过context获取执行测试的方法:
package com.segmentfault.springbootlesson19.listener;
import com.segmentfault.springbootlesson19.domain.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
import org.springframework.test.context.support.AbstractTestExecutionListener;
/**
* TODO
*
* @author <a href="mailto:[email protected]">Mercy</a>
* @see
* @since 2017.09.13
*/
public class PersonIntegrationTestListener extends AbstractTestExecutionListener {
/**
* The default implementation is <em>empty</em>. Can be overridden by
* subclasses as necessary.
*/
@Override
public void prepareTestInstance(TestContext testContext) throws Exception {
/* no-op */
ApplicationContext applicationContext = testContext.getApplicationContext();
Person person = applicationContext.getBean("primaryPerson", Person.class);
System.err.println("person : " + person);
}
/**
* The default implementation is <em>empty</em>. Can be overridden by
* subclasses as necessary.
*/
@Override
public void beforeTestMethod(TestContext testContext) throws Exception {
/* no-op */
System.err.println("before : " + testContext.getTestMethod());
}
/**
* The default implementation is <em>empty</em>. Can be overridden by
* subclasses as necessary.
*/
@Override
public void afterTestMethod(TestContext testContext) throws Exception {
/* no-op */
System.err.println("after : " + testContext.getTestMethod());
}
public final int getOrder(){
return HIGHEST_PRECEDENCE;
}
}
package com.segmentfault.springbootlesson19;
import com.segmentfault.springbootlesson19.configuration.PersonConfiguration;
import com.segmentfault.springbootlesson19.domain.Person;
import com.segmentfault.springbootlesson19.listener.PersonIntegrationTestListener;
import org.junit.*;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
/**
* TODO
*
* @author <a href="mailto:[email protected]">Mercy</a>
* @see
* @since 2017.09.13
*/
@RunWith(SpringRunner.class)
@ContextHierarchy(
@ContextConfiguration(
classes = PersonConfiguration.class
)
)
@TestExecutionListeners(listeners = {
PersonIntegrationTestListener.class,
DependencyInjectionTestExecutionListener.class
})
@TestPropertySource(properties = {"name = 小马哥"})
public class PersonIntegrationTest {
@Value("${name}")
private String name;
@Autowired
private Person person;
@BeforeClass
public static void beforeClass() {
System.err.println("beforeClass()");
}
@Before
public void before() {
System.err.println("before()");
}
@Test
public void testPrimaryPerson() {
Assert.assertEquals(Long.valueOf(1L), person.getId());
Assert.assertEquals("小马哥", person.getName());
Assert.assertEquals(Integer.valueOf(32), person.getAge());
}
@Test
public void testName(){
Assert.assertEquals("小马哥",name);
}
@After
public void after() {
System.err.println("after()");
}
@AfterClass
public static void afterClass() {
System.err.println("afterClass()");
}
}
beforeClass
beforeClass: testMethod
before
after
afterClass: testMethod
afterClass
actuator提供的(technology-agnostic endpoints are available):
举例:configprops
http://localhost:9000/actuator/configprops
SpringFactoriesLoader
META-INF/spring.factories
如果自定义AutoConfiguration在启动文件(@SpringBootApplication注解的main函数文件
)的文件夹下,可以不用将自定义的AutoConfiguration(ApplicationConifg)放到META-INF/spring.factories中,因为默认启动文件所在文件夹下所有文件都会被扫描(
@ComponentScan(basePackages = {"ik.starriver.log"}) )
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.io.support;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.io.UrlResource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* General purpose factory loading mechanism for internal use within the framework.
*
* <p>{@code SpringFactoriesLoader} {@linkplain #loadFactories loads} and instantiates
* factories of a given type from {@value #FACTORIES_RESOURCE_LOCATION} files which
* may be present in multiple JAR files in the classpath. The {@code spring.factories}
* file must be in {@link Properties} format, where the key is the fully qualified
* name of the interface or abstract class, and the value is a comma-separated list of
* implementation class names. For example:
*
* <pre class="code">example.MyService=example.MyServiceImpl1,example.MyServiceImpl2</pre>
*
* where {@code example.MyService} is the name of the interface, and {@code MyServiceImpl1}
* and {@code MyServiceImpl2} are two implementations.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.2
*/
public final class SpringFactoriesLoader {
/**
* The location to look for factories.
* <p>Can be present in multiple JAR files.
*/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
private SpringFactoriesLoader() {
}
/**
* Load and instantiate the factory implementations of the given type from
* {@value #FACTORIES_RESOURCE_LOCATION}, using the given class loader.
* <p>The returned factories are sorted through {@link AnnotationAwareOrderComparator}.
* <p>If a custom instantiation strategy is required, use {@link #loadFactoryNames}
* to obtain all registered factory names.
* @param factoryType the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading (can be {@code null} to use the default)
* @throws IllegalArgumentException if any factory implementation class cannot
* be loaded or if an error occurs while instantiating any factory
* @see #loadFactoryNames
*/
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryType, "'factoryType' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
}
List<T> result = new ArrayList<>(factoryImplementationNames.size());
for (String factoryImplementationName : factoryImplementationNames) {
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
/**
* Load the fully qualified class names of factory implementations of the
* given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
* class loader.
* @param factoryType the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading resources; can be
* {@code null} to use the default
* @throws IllegalArgumentException if an error occurs while loading factory names
* @see #loadFactories
*/
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
@SuppressWarnings("unchecked")
private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {
try {
Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
if (!factoryType.isAssignableFrom(factoryImplementationClass)) {
throw new IllegalArgumentException(
"Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");
}
return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance();
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]",
ex);
}
}
}
Annotation传递性、合并性、继承性
Controller装配方式:
一:RestController注解方式
@RestController
@RequestMapping("/log")
public class EventController {
@Autowired
private EventServiceImpl service;
@Autowired
private DefaultResponseEntity responseEntity;
public EventController(){
....
}
二:Configuration中Bean装配:
ApplicationConfig:
@Configuration
@ConditionalOnProperty(prefix = "event", name = "enabled", havingValue = "true", matchIfMissing = true)
public class ApplicationConfig {
.....
@Bean
public DefaultResponseEntity defaultResponseEntity() {
return new DefaultResponseEntity();
}
@Bean
public EventServiceImpl eventService() {
return new EventServiceImpl();
}
@Bean
public EventController eventController() {
return new EventController();
}
...
}
PS:代码演示了在ApplicationConfig装配Controller,及其需要autowired的bean:DefaultResponseEntity、EventServiceImpl,
这时的DefaultResponseEntity、EventServiceImpl是没有使用@Component和@Service
开发经验(详见相关ppt)
命名经验
启动器名称一般由组件名 + “-spring-boot-starter”后缀
组件名使用名词
比如,payment
启动器名称尽可能言简意赅
正例:payment-spring-boot-starter
启动器名称尽可能避免歧义或者模糊
反例:shopping-spring-boot-starter
启动器名称尽可能避免与官方冲突
反例:spring-boot-starter-web 或 web-spring-boot-starter
自动装配实现经验
自动装配实现类名以“AutoConfiguration”为后缀
正例:PaymentAutoConfiguration
反例:PaymentConfig
组合前置条件尽可能地严谨(多条件)
例如 Spring Boot Web MVC应用的判断
正例:
@ConditionalOnWebApplication
@ConditionalOnClass(Servlet.class)
@ConditionalOnClass(DispatcherServlet.class)
反例:
@ConditionalOnWebApplication
自动装配实现经验
组合前置条件判断成本由低到高(多条件)
假设当@ConditionalOnClass 和 @ConditionalOnBean 同时存在时,@ConditionalOnClass 的判断成本较低,因此放置的位置优先。
例如:
@ConditionalOnClass(Car.class)
@ConditionalOnBean(JpaRepository.class)
public class VehicleAutoConfiguration {}
自动装配Class 组件依赖与顺序尽可能明确
@ConfiguraionProperties Class 应生成原信息
spring-boot-configuration-processor
类库依赖经验
明确知晓第三方类库依赖范围
类库依赖应做到最小化原则
通用工具类尽可能使用 Spring 内部,而非 Apache Commons
Spring Boot 依赖管理尽量保持<optional> = true
类库依赖经验
明确知晓第三方类库依赖范围
类库依赖应做到最小化原则
通用工具类尽可能使用 Spring 内部,而非 Apache Commons
Spring Boot 依赖管理尽量保持<optional> = true
bean的加载顺序要参考该Bean内部是否是树形依赖关系,比如有构造器的Bean Class,会先加载构造器依赖的Bean:
@RestController
public class PersonRestController {
private final Person person;
public PersonRestController(Person person) {
this.person = person;
}
@GetMapping("/person")
public Person person() {
return person;
}
}
也可以通过bean中的依赖关系查看加载顺序:
为什么构造器注入不加@Autowire也可以实现,参考源码:
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
不建议使用的方法,通过@Deprecated注解,不要删除,提供兼容性
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*/
package java.lang;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
/**
* A program element annotated @Deprecated is one that programmers
* are discouraged from using, typically because it is dangerous,
* or because a better alternative exists. Compilers warn when a
* deprecated program element is used or overridden in non-deprecated code.
*
* @author Neal Gafter
* @since 1.5
* @jls 9.6.3.6 @Deprecated
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
看源码
第六点, 同样的需求通过不同的实现方式来实现
兼容并包,课程结束!