spring系列课程 spring boot(mercyblitze)8-20

一对一

 

实例

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);
		}
	}
    
    .....
}

 

Kafka

 

 

producer serialize 发送数据(object -> outputStream write --> byteArrray)

consumer deserialize 接受到的数据 (byteArrray --> inputStream readObject --> Object)

 

spring.kafka.BOOTSTRAP-SERVERS=localhost:9091,localhost:9092,localhost:9093
spring.kafka.consumer.group-id=sf-group
spring.kafka.consumer.clientId=sf-client-1


# 生产者 值的序列化
spring.kafka.producer.valueSerializer = com.segmentfault.springbootlesson11.serializer.ObjectSerializer

# 消费者 值的反序列化
spring.kafka.consumer.valueDeserializer = com.segmentfault.springbootlesson11.deserializer.ObjectDeserializer

 

 

 

commons.apache.org

ComponentsDescriptionLatest VersionReleased
BCELByte Code Engineering Library - analyze, create, and manipulate Java class files6.3.12019-03-24
BeanUtilsEasy-to-use wrappers around the Java reflection and introspection APIs.1.9.42019-08-13
BSFBean Scripting Framework - interface to scripting languages, including JSR-2233.12010-06-24
ChainChain of Responsibility pattern implemention.1.22008-06-02
CLICommand Line arguments parser.1.42017-03-09
CodecGeneral encoding/decoding algorithms (for example phonetic, base64, URL).1.132019-07-23
CollectionsExtends or augments the Java Collections Framework.4.42019-07-08
CompressDefines an API for working with tar, zip and bzip2 files.1.192019-08-27
ConfigurationReading of configuration/preferences files in various formats.2.52019-05-27
CryptoA cryptographic library optimized with AES-NI wrapping Openssl or JCE algorithm implementations.1.0.02016-07-22
CSVComponent for reading and writing comma separated value files.1.72019-06-05
DaemonAlternative invocation mechanism for unix-daemon-like java code.1.0.152013-04-03
DBCPDatabase connection pooling services.2.7.02019-08-07
DbUtilsJDBC helper library.1.72017-07-20
DigesterXML-to-Java-object mapping utility.3.22011-12-13
EmailLibrary for sending e-mail from Java.1.52017-08-01
ExecAPI for dealing with external process execution and environment management in Java.1.32014-11-06
FileUploadFile upload capability for your servlets and web applications.1.42019-01-16
FunctorA functor is a function that can be manipulated as an object, or an object representing a single, generic function.1.02011-??-??
GeometrySpace and coordinates.1.02018-??-??
Imaging (previously called Sanselan)A pure-Java image library.1.0-alpha12019-05-02
IOCollection of I/O utilities.2.62017-10-15
JCIJava Compiler Interface1.12013-10-14
JCSJava Caching System2.2,12018-08-23
JellyXML based scripting and processing engine.1.0.12017-09-27
JexlExpression language which extends the Expression Language of the JSTL.3.12017-04-14
JXPathUtilities for manipulating Java Beans using the XPath syntax.1.32008-08-14
LangProvides extra functionality for classes in java.lang.3.92019-04-15
LoggingWrapper around a variety of logging API implementations.1.22014-07-11
MathLightweight, self-contained mathematics and statistics components.3.52015-04-17
NetCollection of network utilities and protocol implementations.3.62017-02-15
NumbersNumber types (complex, quaternion, fraction) and utilities (arrays, combinatorics).1.02017-??-??
OGNLAn Object-Graph Navigation Language4.02013-??-??
PoolGeneric object pooling component.2.7.02019-07-29
ProxyLibrary for creating dynamic proxies.1.02008-02-28
RDFCommon implementation of RDF 1.1 that could be implemented by systems on the JVM.0.3.0-incubating2016-11-15
RNGImplementations of random numbers generators.1.22018-12-12
SCXMLAn 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.92008-12-01
StatisticsStatistics.0.1????-??-??
TextApache Commons Text is a library focused on algorithms working on strings.1.82019-09-02
ValidatorFramework to define validators and validation rules in an xml file.1.62017-02-21
VFSVirtual File System component for treating files, FTP, SMB, ZIP and such like as a single logical file system.2.4.12019-08-15
WeaverProvides an easy way to enhance (weave) compiled bytecode.2.02018-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:mercyblitz@gmail.com">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查看加载顺序

http://localhost:5678/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"
    }
}

查看具体某个属性

http://localhost:5678/env/url

{
    "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:mercyblitz@gmail.com">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:mercyblitz@gmail.com">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

 

https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#spring-testing-annotation-testexecutionlisteners

actuator提供的(technology-agnostic endpoints are available):

https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready

举例: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 &#64;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 {
}

 

 

 

 看源码

第六点, 同样的需求通过不同的实现方式来实现 

兼容并包,课程结束!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值