在java中梦抢,在不改變源代碼的情況下般贼,實現(xiàn)方法增強的方式有三種:
- 1,繼承
- 2奥吩,裝飾者模式
- 3哼蛆,代理模式(靜態(tài)代理和動態(tài)代理)
1,繼承模式:
- 簡單來說霞赫,就是通過繼承的方式腮介,在子類方法中添加相應(yīng)的增強方法,然后通過調(diào)用子類方法來實現(xiàn)增強绩脆。
//繼承比較簡單萤厅,直接繼承,重寫中調(diào)用父類方法即可
2靴迫,裝飾者模式:
- 裝飾者模式是真正完全不改變源碼的情況下增強方法的一種方式惕味,即便是調(diào)用方式也無需改變
- 這里用自定義的連接池來進(jìn)行說明
- 在自定義連接池中,如果沒有增強過Connection的話玉锌,那么是不能按照原來的方式直接調(diào)用connection.close();方法的名挥,那么可以通過裝飾,把連接池中的Connection對象直接在放入池之前包裝成我自定義的Connection主守,這樣從連接池中取出來的連接也是我自定義的連接禀倔,那么只需要在自定義的方法中實現(xiàn)close()和prepareStatement等就可以達(dá)到直接調(diào)用關(guān)閉方法的目的榄融,具體如下:
//1,自定義連接池
/*
* 對JDBC連接的封裝救湖,也就是自定義連接池
* 其他一些方法也需要重寫愧杯,但是不需要任何改變,所以這里就沒有貼出來
*/
public class JDBCDatasource implements DataSource {
private static LinkedList<Connection> connections = new LinkedList<Connection>();
//往連接池中添加連接
static{
for(int i=0;i<5;i++){
Connection connection = JDBCUtil.getConnection();
JDBCConnection theConnection = new JDBCConnection(connections, connection);
connections.add(theConnection);
}
}
//重寫這一個方法鞋既,如果沒有增強過connection的話力九,需要調(diào)用這個方法歸還連接到連接池中
@Override
public Connection getConnection() throws SQLException {
if (connections.size() == 0) {
for(int i=0;i<5;i++){
Connection connection = JDBCUtil.getConnection();
JDBCConnection theConnection = new JDBCConnection(connections, connection);
connections.add(theConnection);
}
}
return connections.removeFirst();
}
//新增一個方法
public void returnConnection(Connection connection){
connections.add(connection);
}
}
//2,自定義連接類邑闺,實現(xiàn)相應(yīng)的方法跌前,并在自定義的連接池中進(jìn)行包裝,具體看1中的代碼
//其他一些不需要修改的覆蓋方法這里不再貼出
public class JDBCConnection implements Connection {
private Connection connection;
private LinkedList<Connection> connections;
public JDBCConnection(List<Connection> connections, Connection connection) {
this.connections = (LinkedList<Connection>) connections;
this.connection = connection;
}
//如果想要在關(guān)閉的時候添加到連接池陡舅,那么需要把連接池傳進(jìn)來抵乓,傳進(jìn)來最好的時候就是創(chuàng)建的時候
@Override
public void close() throws SQLException {
System.out.println("here here!");
connections.add(connection);
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return connection.prepareStatement(sql);
}
}
//測試
JDBCDatasource datasource = new JDBCDatasource();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = datasource.getConnection();
preparedStatement = connection.prepareStatement("select * from product;");
resultSet = preparedStatement.executeQuery();
while(resultSet.next()){
System.out.println(resultSet.getString("pname"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//這行代碼中封裝了connection.close()方法
JDBCUtil.closeAll(connection, preparedStatement, resultSet);
}
3,代理模式:
- 代理分為動態(tài)代理和靜態(tài)代理靶衍,區(qū)別就是靜態(tài)代理是自己創(chuàng)建一個代理類灾炭,實現(xiàn)相應(yīng)的被代理對象的方法,增加相應(yīng)的增強代碼摊灭。而動態(tài)代理是通過類加載器咆贬,反射等在運行時創(chuàng)建代理類,也就是不需要手動創(chuàng)建代理類帚呼,在對應(yīng)的代理方法newProxyInstance中的代碼塊中直接添加增強代碼掏缎;
- 動態(tài)代理是在靜態(tài)代理的基礎(chǔ)上的拓展,所以先看下靜態(tài)代理:
//1,首先需要有一個接口類煤杀,方便目標(biāo)對象和代理對象去實現(xiàn)
public interface DogInterface {
public void eat();
public void run();
}
//2眷蜈,目標(biāo)對象中實現(xiàn)借口類
public class Dog implements DogInterface {
@Override
public void eat() {
System.out.println("Dog -----eat");
}
@Override
public void run() {
System.out.println("dog----run----");
}
}
//3,創(chuàng)建一個代理對象,在代理對象中實現(xiàn)借口類沈自,并在對應(yīng)的方法中調(diào)用目標(biāo)對象的方法酌儒。
public class DogProxy implements DogInterface {
@Override
public void eat() {
System.out.println("dog在eat前,準(zhǔn)備工作代碼等");
//這里調(diào)用目標(biāo)對象的方法
Dog dog = new Dog();
dog.eat();
System.out.println("dog在eat后收尾工作代碼等");
}
@Override
public void run() {
}
}
//4,實際使用時候使用代理對象即可
public void proxyTest(){
DogProxy proxy = new DogProxy();
proxy.eat();//這里就ok了
}
- 下面是動態(tài)代理的代碼實現(xiàn)枯途,前兩步是完全一致的
有一點需要注意的是:動態(tài)代理方法雖然能增強方法忌怎,但主要的使用場合是在攔截中進(jìn)行相應(yīng)的處理,如在全局的攔截器中進(jìn)行亂碼處理等
//1,首先需要有一個接口類酪夷,方便目標(biāo)對象和代理對象去實現(xiàn)
public interface DogInterface {
public void eat();
public void run();
}
//2榴啸,目標(biāo)對象中實現(xiàn)借口類
public class Dog implements DogInterface {
@Override
public void eat() {
System.out.println("Dog -----eat");
}
@Override
public void run() {
System.out.println("dog----run----");
}
}
//3,在調(diào)用的時候使用代理類調(diào)用靜態(tài)方法創(chuàng)建動態(tài)代理
public void dynamicProxyTest(){
DogInterface proxy = (DogInterface) Proxy.newProxyInstance(
Dog.class.getClassLoader(),
Dog.class.getInterfaces(), //new Class[]{DogInterface.class}
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
method.invoke(new Dog(), args);
System.out.println("after");
return null;
}
});
proxy.eat();
proxy.run();
}
//搞定晚岭!