IoC : Inversion of Control
spring是通過依賴注入(Dependency Injection )實現(xiàn)的IoC
IoC容器
* 必須將被管理的對象定義到spring配置文件中
* 必須定義constructor或者setter方法,讓spring將對象注入進去
AOP : Aspect Oriented Programming
spring帶來了一種編程方式,面向切面的編程。
AOP是一個概念
在一個程序中分離一個功能,這種功能的實現(xiàn)是與程序不相關(guān)的類。
同時能夠使很多類共享這個功能。
關(guān)注是他的主要點,要關(guān)注某個功能,要關(guān)注切入點。
實現(xiàn)AOP有2點:
1、Pointcut(切入點)是一個范圍---表達式
2、Advice(具體實現(xiàn))功能放到那個方法
spring對hibernate的支持
注入SessionFactory到spring配置文件中
<Bean id="SessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactory">
<property nema="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</Bean>
在網(wǎng)上看過很多解決mysql亂碼的帖子,可是寫的不是羅里羅嗦就過于復(fù)雜。其實亂碼沒那么復(fù)雜,是網(wǎng)上的大俠們想多了。我研究過一段日子,總結(jié)出一套自己的解決方案,如果你還沒解決亂碼就用我的方法試一下。我的方案不是最好的,卻是最簡單易懂的。不信你試試。
在使用MYSQL時,插入中文字符,經(jīng)常會出現(xiàn)亂碼,中文全被用?代替。出現(xiàn)這種情況的原因,多是字符集不匹配造成的。
在MYSQL中,如果使用缺省的字符集,在建庫、建表時,默認(rèn)使用的是latin1字符集,為ISO 8859-1西歐字符集。插入中文字符時,與之不匹配,就會出現(xiàn)亂碼。
要解決此問題,就必須手動將數(shù)據(jù)庫Server和Client的字符編碼改為gb2312。配置方法如下:
打開MYSQL安裝目錄下的my.ini文件,找到如下段落:
# CLIENT SECTION
# ----------------------------------------------------------------------
#
# The following options will be read by MySQL client applications.
# Note that only client applications shipped by MySQL are guaranteed
# to read this section. If you want your own MySQL client program to
# honor these values, you need to specify it as an option during the
# MySQL client library initialization.
#
[client]
port=3306
[mysql]
default-character-set=latin1
# SERVER SECTION
# ----------------------------------------------------------------------
#
# The following options will be read by the MySQL Server. Make sure that
# you have installed the server correctly (see above) so it reads this
# file.
#
[mysqld]
# The TCP/IP Port the MySQL Server will listen on
port=3306
#Path to installation directory. All paths are usually resolved relative to this.
basedir="D:/MySQL/MySQL Server 5.0/"
#Path to the database root
datadir="D:/MySQL/MySQL Server 5.0/Data/"
# The default character set that will be used when a new schema or table is
# created and no character set is defined
default-character-set=latin1
將其中的default-character-set=latin1改為default-character-set=gb2312( 兩個都改),然后重啟MYSQL(特別注意:以前建立的數(shù)據(jù)庫要重建,因為以前存儲的數(shù)據(jù)編碼方式為ISO-8859-1),運行MySQL Command Line Client:
輸入show variables like 'character_set_%';可以查看數(shù)據(jù)庫的字符編碼如下:
mysql> show variables like 'character_set_%';
+--------------------------+-----------------------------------------+
| Variable_name | Value |
+--------------------------+-----------------------------------------+
| character_set_client | gb2312 |
| character_set_connection | gb2312 |
| character_set_database | gb2312 |
| character_set_filesystem | binary |
| character_set_results | gb2312 |
| character_set_server | gb2312 |
| character_set_system | utf8 |
| character_sets_dir | D:\MySQL\MySQL Server 5.0\share\charsets|
+--------------------------+-----------------------------------------+
然后,在程序中將連接數(shù)據(jù)庫的URL改為jdbc:mysql://localhost:3306/databasename?useUnicode=true&characterEncoding=gb2312 就可以了!(&;是代表xml中的&)
還需要注意到是:1.你的JSP頁面一定別忘了加上編碼方式<%@ page pageEncoding="GB2312"%>。
2.把以前寫過濾方法如:getbytes(iso-8859-1)全去掉
最后記住,一定要重新導(dǎo)入或建立數(shù)據(jù)庫!!!
單態(tài)定義:
Singleton模式主要作用是保證在Java應(yīng)用程序中,一個類Class只有一個實例存在。
Singleton模式就為我們提供了這樣實現(xiàn)的可能。使用Singleton的好處還在于可以節(jié)省內(nèi)存,因為它限制了
實例的個數(shù),有利于Java垃圾回收(garbage collection)。
使用Singleton注意事項:
有時在某些情況下,使用Singleton并不能達到Singleton的目的,如有多個Singleton對象同時被不同的類
裝入器裝載;在EJB這樣的分布式系統(tǒng)中使用也要注意這種情況,因為EJB是跨服務(wù)器,跨JVM的
單態(tài)模式的演化:
單態(tài)模式是個簡單的模式,但是這個簡單的模式也有很多復(fù)雜的東西。
一,首先最簡單的單態(tài)模式,單態(tài)模式1
import java.util.*;
class Singleton
{
private static Singleton instance;
private Vector v;
private boolean inUse;
private Singleton()
{
v = new Vector();
v.addElement(new Object());
inUse = true;
}
public static Singleton getInstance()
{
if (instance == null) //1
instance = new Singleton(); //2
return instance; //3
}
}
這個單態(tài)模式是不安全的,為什么說呢 ?因為沒考慮多線程,如下情況
Thread 1 調(diào)用getInstance() 方法,并且判斷instance是null,然後進入if模塊,
在實例化instance之前,
Thread 2搶占了Thread 1的cpu
Thread 2 調(diào)用getInstance() 方法,并且判斷instance是null,然後進入if模塊,
Thread 2 實例化instance 完成,返回
Thread 1 再次實例化instance
這個單態(tài)已經(jīng)不在是單態(tài)
二,為了解決剛才的問題:單態(tài)模式2
public static synchronized Singleton getInstance()
{
if (instance == null) //1
instance = new Singleton(); //2
return instance; //3
}
采用同步來解決,這種方式解決了問題,但是仔細分析
正常的情況下只有第一次時候,進入對象的實例化,須要同步,
其它時候都是直接返回已經(jīng)實例化好的instance不須要同步,
大家都知到在一個多線程的程序中,如果同步的消耗是很大的,很容易造成瓶頸
三,為了解決上邊的問題:單態(tài)模式3,加入同步
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
同步改成塊同步,而不使用函數(shù)同步,但是仔細分析,
又回到了模式一的狀態(tài),再多線程的時候根本沒有解決問題
四,為了對應(yīng)上邊的問題:單態(tài)模式4,也就是很多人采用的Double-checked locking
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
if (instance == null) //2
instance = new Singleton(); //3
}
}
return instance;
}
這樣,模式一中提到的問題解決了。不會出現(xiàn)多次實例化的現(xiàn)象
當(dāng)?shù)谝淮芜M入的時候,保正實例化時候的單態(tài),在實例化后,多線程訪問的時候直接返回,不須要進入同步模塊,
既實現(xiàn)了單態(tài),又沒有損失性能。表面上看我們的問題解決了,但是再仔細分析:
我們來假象這中情況:
Thread 1 :進入到//3位置,執(zhí)行new Singleton(),但是在構(gòu)造函數(shù)剛剛開始的時候被Thread2搶占cpu
Thread 2 :進入getInstance(),判斷instance不等于null,返回instance,
(instance已經(jīng)被new,已經(jīng)分配了內(nèi)存空間,但是沒有初始化數(shù)據(jù))
Thread 2 :利用返回的instance做某些操做,失敗或者異常
Thread 1 :取得cpu初始化完成
過程中可能有多個線程取到了沒有完成的實例,并用這個實例作出某些操做。
-----------------------------------------
出現(xiàn)以上的問題是因為
mem = allocate(); //分配內(nèi)存
instance = mem; //標(biāo)記instance非空
//未執(zhí)行構(gòu)造函數(shù),thread 2從這里進入
ctorSingleton(instance); //執(zhí)行構(gòu)造函數(shù)
//返回instance
------------------------------------------
五,證明上邊的假想是可能發(fā)生的,字節(jié)碼是用來分析問題的最好的工具,可以利用它來分析
下邊一段程序:(為了分析方便,所以漸少了內(nèi)容)
字節(jié)碼的使用方法見這里,利用字節(jié)碼分析問題
class Singleton
{
private static Singleton instance;
private boolean inUse;
private int val;
private Singleton()
{
inUse = true;
val = 5;
}
public static Singleton getInstance()
{
if (instance == null)
instance = new Singleton();
return instance;
}
}
得到的字節(jié)碼
;asm code generated for getInstance
054D20B0 mov eax,[049388C8] ;load instance ref
054D20B5 test eax,eax ;test for null
054D20B7 jne 054D20D7
054D20B9 mov eax,14C0988h
054D20BE call 503EF8F0 ;allocate memory
054D20C3 mov [049388C8],eax ;store pointer in
;instance ref. instance
;non-null and ctor
;has not run
054D20C8 mov ecx,dword ptr [eax]
054D20CA mov dword ptr [ecx],1 ;inline ctor - inUse=true;
054D20D0 mov dword ptr [ecx+4],5 ;inline ctor - val=5;
054D20D7 mov ebx,dword ptr ds:[49388C8h]
054D20DD jmp 054D20B0
上邊的字節(jié)碼證明,猜想是有可能實現(xiàn)的
六:好了,上邊證明Double-checked locking可能出現(xiàn)取出錯誤數(shù)據(jù)的情況,那么我們還是可以解決的
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
Singleton inst = instance; //2
if (inst == null)
{
synchronized(Singleton.class) { //3
inst = new Singleton(); //4
}
instance = inst; //5
}
}
}
return instance;
}
利用Double-checked locking 兩次同步,中間變量,解決上邊的問題。
(下邊這段話我只能簡單的理解,翻譯過來不好,所以保留原文,list 7是上邊的代碼,list 8是下邊的
The code in Listing 7 doesn't work because of the current definition of the memory model.
The Java Language Specification (JLS) demands that code within a synchronized block
not be moved out of a synchronized block. However, it does not say that
code not in a synchronized block cannot be moved into a synchronized block.
A JIT compiler would see an optimization opportunity here.
This optimization would remove the code at
//4 and the code at //5, combine it and generate the code shown in Listing 8:)
-------------------------------------------------
list 8
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
Singleton inst = instance; //2
if (inst == null)
{
synchronized(Singleton.class) { //3
//inst = new Singleton(); //4
instance = new Singleton();
}
//instance = inst; //5
}
}
}
return instance;
}
If this optimization takes place, you have the same out-of-order write problem we discussed earlier.
如果這個優(yōu)化發(fā)生,將再次發(fā)生上邊提到的問題,取得沒有實例化完成的數(shù)據(jù)。
-------------------------------------------------
以下部分為了避免我翻譯錯誤誤導(dǎo)打家,保留原文
Another idea is to use the keyword volatile for the variables inst and instance.
According to the JLS (see Resources), variables declared volatile are supposed to
be sequentially consistent, and therefore, not reordered.
But two problems occur with trying to use volatile to fix the problem with
double-checked locking:
The problem here is not with sequential consistency.
Code is being moved, not reordered.
Many JVMs do not implement volatile correctly regarding sequential consistency anyway.
The second point is worth expanding upon. Consider the code in Listing 9:
Listing 9. Sequential consistency with volatile
class test
{
private volatile boolean stop = false;
private volatile int num = 0;
public void foo()
{
num = 100; //This can happen second
stop = true; //This can happen first
//...
}
public void bar()
{
if (stop)
num += num; //num can == 0!
}
//...
}
According to the JLS, because stop and num are declared volatile,
they should be sequentially consistent. This means that if stop is ever true,
num must have been set to 100.
However, because many JVMs do not implement the sequential consistency feature of volatile,
you cannot count on this behavior.
Therefore, if thread 1 called foo and thread 2 called bar concurrently,
thread 1 might set stop to true before num is set to 100.
This could lead thread 2 to see stop as true, but num still set to 0.
There are additional problems with volatile and the atomicity of 64-bit variables,
but this is beyond the scope of this article.
See Resources for more information on this topic.
簡單的理解上邊這段話,使用volatile有可能能解決問題,volatile被定義用來保正一致性,但是很多虛擬機
并沒有很好的實現(xiàn)volatile,所以使用它也會存在問題。
最終的解決方案:
(1),單態(tài)模式2,使用同步方法
(2),放棄同步,使用一個靜態(tài)變量,如下
class Singleton
{
private Vector v;
private boolean inUse;
private static Singleton instance = new Singleton();
private Singleton()
{
v = new Vector();
inUse = true;
//...
}
public static Singleton getInstance()
{
return instance;
}
}
但使用靜態(tài)變量也會存在問題,問題見 這篇文章
而且如在文章開頭提到的,使用EJB跨服務(wù)器,跨JVM的情況下,單態(tài)更是問題
好了是不是感覺單態(tài)模式根本沒法使用了,其實上邊都是特殊情況,這中特殊情況的出現(xiàn)是有條件的,只要
根據(jù)你的具體應(yīng)用,回避一些,就能解決問題,所以單態(tài)還是可以使用的。但是在使用前慎重,自己考慮好自己
的情況適合哪種情況。
我有很多概念都沒明白,現(xiàn)在反過頭來認(rèn)識。
Object是所有類的父類。
java.lang.String也是繼承自java.lang.Object中。
先比較一下2個類的toString()、equals()、= = (很多面試題都有),再來說一下String 的特殊。
2個類toString()的比較:
查閱API文檔:
說明String類重寫了Object的toString方法。
2個類equals()、= =比較:
"=="是比較2個對象的引用是否指向同一個地址,如果是比較2個基本類型,那么就是比較2個值是否相等。
我new了2個Dog類,他們2個對象的棧引用肯定不能指向同一個堆地址。第二個String對象"=="的比較也是同樣道理。所以都返回了false(第三個比較體現(xiàn)了String的特殊類,等下說明)。
查閱jdk的源代碼:"equals"在Object中定義為
這就表示一個類如果沒有重寫該方法的話,它就是比較兩個的引用是否指向了同一個地址(和"=="比較是一致的)。
類庫里的類基本都重寫的該方法,所以是比較2個對象的內(nèi)容是否一樣的(String方法重寫了該方法,所以第二個equals比較返回ture),對于外面自己自定義的類,則需要自己重寫該方法來達到內(nèi)容是否相等的邏輯。
特殊對象String的equals()、= =比較:
String s = newString("abc");和String s = "abc";
首先2個對象在內(nèi)存分布上是不一樣的。第2個對象是s的棧引用指向數(shù)據(jù)片段區(qū)的地址(存放字符串常量,靜態(tài)成員變量)。第1個new出來的對象是s的棧引用指向堆中的地址(存放在堆中)。通過API文檔:新創(chuàng)建的字符串對象s是該參數(shù)字符串("abc")的副本。
所以如代碼所表示:"=="比較是不一樣的,equals方法由于String重寫了,比較是字符序列。
String s1 = "abc" 和 String s2 = "abc"比較;
"=="和equals方法都返回ture;
s1分配了字符常量"abc",那么再有"abc"要引用給對象,都不會再分配內(nèi)存空間了。
所以s1 和s2 指向的空間相同,內(nèi)容也相同。