Spring profile allows conditional registration of beans/components in runtime based on constants specified declaratively in configuration or programmatically in code. Let see some use cases.
Activate @Component based on active profile
Suppose we have a service interface called SomeService which has a method called doSomething:
1 2 3 4
// In SomeService.java publicinterfaceSomeService { voiddoSomething(); }
SomeService should only do real work in production environment and trivials in others. We can do this way:
1 2 3 4 5 6 7 8 9
// In SomeServiceImpl.java @Service @Profile("production") publicclassSomeServiceImplimplementsSomeService { @Override publicvoiddoSomething() { // Do real work ... } }
1 2 3 4 5 6 7 8
@Service @Profile("!production") publicclassNoOpSomeServiceImplimplementsSomeService { @Override publicvoiddoSomething() { // Do trivial things ... } }
Now, based on whether production profile is declared or not, SomeServiceImpl or NoOpSomeServiceImpl will serve requests as SomeService.
Register @Bean based on active profile
1 2 3 4 5 6 7 8
@Configuration publicclassWebConfiguration { @Bean @Profile({"dev", "!featureA"}) public CustomBean customBean() { // instantiate, configure and return bean ... } }
Recently, I and my colleague build a small web project together using Spring.
We use a context path other than “/”, say, “/abc” which is the project name.
This setting is consistent with existing projects in my team.
But after we deploy this project behind nginx, we encounter problem. In nginx, we
config something like this:
It works fine for handwritten url from client. But the url links in the response html,
which is generated by this application and points to resources inside this application,
does not work. All url forwarded by nginx will be prefixed with “/abc”, which is the
context path of this application in web container. While the application generated url
links have that prefix already. This results in wrong url links for those resources.
There are workarounds to solve this, though, but after investigation and thinking, I
concludes to:
If you use reverse proxy to forward HTTP request, then don’t use context path in your
application, instead let reverse proxy set context path for you.
First, if you use context path other than “/” in your application and you want your application
visited via top domain without subpath, then you must hardcode that context path in reverse
proxy. The same information is hardcoded in two places, your application and the reverse proxy.
Second, if you use context path “/” in your application and you want your application visited via
subpath, reverse proxy such as nginx can set X-Forwarded-Prefix for your application to generate
url links prefixed with that subpath. If the framework backing your application respect this header,
you probably don’t notice that.
The underlying cause behind this conclusion is that both web application and reverse proxy are
passive. They accept request, handle it, response it. The solution comes from the fact that reverse
proxy stand before web application so that it can add extra informations for web application to handle
in programming approach without the need to handcode such informations.
Recently, I write a LevelDBimplementation in Go. In this post, I summarize
some invariants in algorithm used by LevelDB implementations.
Sequence Number
Sequence number is a monotonically increasing 56 bits integer value. Every
time a key is written to LevelDB, it is tagged with a sequence number one
larger than sequence number tagged with previous key written to LevelDB. If two entries in LevelDB have same user level keys, the one with larger
sequence must shadow the other.
Sorted Memory Tables
Writes are first recorded in a mutable memory table. If that memory table is
full, it is marked as immutable and a new memory table is created to record
writes. The memory table marked as immutable is then compacted to a sorted
disk table in level 0 and deleted. Thus we conclude that:
If a key appears in mutable memory table, it is newest. Otherwise, if it
appears in immutable memory table, it is newest.
Compaction
When an immutable memory table is compacted to a sorted table in Level 0, it
is assigned with a file number larger than all existing file numbers in this
Level. Thus we have:
Entries stored in newer file in Level 0 shadow entries with same user keys
in older files.
When there are too many files in Level 0 or too many data in Level 1 or above,
we start level compaction. In level N compaction, we select a file set from
level N, such that no remaining files overlap this file set in user key level.
Then we compact this file set with all overlapping files from level N+1, and
produce sorted tables in level N+1. Thus we conclude to two invariants.
People coming from C or C++ may think that there is no memory leak in languages with garbage collection. But the truth is:
Memory leak does exist in languages with automatic garbage collection.
In perspective of human beings, garbage means something will never being used after sometime. Unfortunately, computer can’t
understand this. Computer uses a concept unreachable to detect whether
an object is garbage or not. There is a gap, as you may already known, that is “reachable but no longer used”.
Here, I show you a memory leak case using Go. Also, it can happen in other garbage collection language, like Java.
Goroutine is so lightweight and convenient in Go. Sometimes, you may use it to do some background jobs.
Suppose, I write following code for a database library:
You may find that, database object created in function test is a garbage, but it never and will never got collected.
The object is reachable from function backgroundWork called in goroutine fired by go backgroundWork(db) in Open.
If we want garbage collector to collect object for us, we should not reference the object in any case. In above code,
we should not reference database object in backgroundWork. Let us make some changes: