代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
Spring 为解耦而诞生,其中AOP(面向切面编程)是很浓重的一笔。
这里简单记录一下AOP 给我带来的好处:
1.
用了一段时间,想通过简单的代码,更好的阐述以及理解它。
以前:假设我们有个简单的业务,还是经典的Hello World,那么我们定义一个Service 接口,一个ServiceImpl 实现类,一个sayHello 方法,这里使用网上很经典的日志记录的例子。
1.Service接口:定义一个sayHello 的业务方法
- public interface Service {
- public void sayHello();
- }
2.ServiceImpl实现类:主要是打印HelloWord,但是日常项目中,在主要业务前后可能会添加日志记录,或者开启事务等其他必要操作。
- public class ServiceImpl implements Service{
- @Override
- public void sayHello() {
- System.out.println("前置日记:打印、启动事务等..");
- System.out.println("Hello world!");
- System.out.println("后置日记:打印、关闭事务等..");
- }
- }
例子很简单,那么假设,我们不光拥有sayHello ,还有sayBye 等多个方法,并且都需要其他操作呢?那么你是不是会写很多个这样的,重复的代码?
当然,你可以减少一部分工作量,你可以这样:
- public class ServiceImpl implements Service{
- @Override
- public void sayHello() {
- before();
- System.out.println("Hello world!");
- after();
- }
- @Override
- public void sayBye() {
- before();
- System.out.println("Bye bye!");
- after();
- }
- public static void before(){
- System.out.println("前置日记:打印、启动事务等..");
- }
- public static void after(){
- System.out.println("后置日记:打印、关闭事务等..");
- }
- }
我们再次假设,如果我们拥有更多的业务方法:sayHi(),sayOther()....,需要更多的其他操作:打印信息,传输记录....。并且其他ServiceImpl 里面的方法也需要这些方法呢?那么我们是不是每个类又要继续添加呢?
当然,你可以这样做:建立一个对Service 添加额外功能的类,统一提供。
- public class ServiceFactory {
- public static void before(){
- System.out.println("前置日记:打印、启动事务等..");
- }
- public static void after(){
- System.out.println("后置日记:打印、关闭事务等..");
- }
- public static void other(){
- System.out.println("做其他的事..");
- }
- }
ServiceImpl 就成这样:
- public class ServiceImpl implements Service{
- @Override
- public void sayHello() {
- ServiceFactory.before();
- System.out.println("Hello world!");
- ServiceFactory.after();
- }
- @Override
- public void sayBye() {
- ServiceFactory.before();
- System.out.println("Bye bye!");
- ServiceFactory.after();
- }
- @Override
- public void sayHi() {
- ServiceFactory.before();
- System.out.println("Hi");
- ServiceFactory.after();
- ServiceFactory.other();
- }
- }
这样代码,感觉是少了一些,但是我们的原则是尽量 别重复同样的代码,提高代码的复用性,改动最小为基准。也许业务很复杂,比较多,那么你要重复多少代码,整个类要写得多麻烦所啊!如果到时候有些假设before 和after 需要变化位置,你又要改动多少呢?
当然,目前的的JDK (大于1.3)为了解决这些问题,为我们提供的反射机制,动态代理机制。看看如何更好的解决这个问题。这里先copy 下,什么是代理:
Java的动态代理机制
代理模式是常用的Java设计模式。代理类主要负责为委托类预处理消息、过滤信息、把消息转发给委托类,以及事后处理信息等。
理论 - -总是那么抽象(~。~),简单点说,就是:1.我的目的是去学校,那么校服 早餐 校车,这些我都需要,但是不由我做,全部代理给我父母搞定了(当然我是自己搞定的。)2.再简单的说就是:我只关注我主要的事情,其他附加的事情,全部交给别人搞定。看代码..
MyPorxy 我的代理类:
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- public class MyProxy implements InvocationHandler{
- // 目标对象,也就是我们主要的业务,主要目的要做什么事
- private Object delegate;
- /**
- * 和你额外需要做得事情,进行绑定,返回一个全新的对象(写法,基本上固定的)
- * @param delegate
- * @return
- */
- public Object bind(Object delegate){
- this.delegate = delegate;
- return Proxy.newProxyInstance(this.delegate.getClass().getClassLoader(),
- this.delegate.getClass().getInterfaces(), this);
- }
- /**
- * 你刚才需要执行的方法,都需要通过该方法进行动态调用
- */
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object obj = null;
- // 执行前置的方法
- ServiceFactory.before();
- // 通过反射,执行目标方法,也就是你的主要目的
- obj = method.invoke(this.delegate, args);
- // 执行后置的方法
- ServiceFactory.after();
- // 返回值给调用者
- return obj;
- }
- }
这里运用的反射知识,还需要去看看,这里就不解释了。
ServiceImpl 变化:
- public class ServiceImpl implements Service{
- @Override
- public void sayHello() {
- System.out.println("Hello world!");
- }
- @Override
- public void sayBye() {
- System.out.println("Bye bye!");
- }
- @Override
- public void sayHi() {
- System.out.println("Hi");
- }
- }
测试类:
- public class Test {
- /**
- * 测试类
- * @param args
- */
- public static void main(String[] args) {
- // 不启用代理
- //Service service = new ServiceImpl();
- // 使用代理
- Service service = (Service)new MyProxy().bind(new ServiceImpl());
- service.sayHello();
- service.sayBye();
- service.sayHi();
- }
- }
OK,那么你现在看看,我们的业务实现类ServiceImpl 是不是干净多了,代码是不是在某些地方见过呢?即时你再进行添加更多的方法,也可以同样实现了对吗?当然,在Test里面,假设我们有的方法想用,有的方法不想用,那么又该怎么实现呢?
详细介绍:
代理(Proxy)有两种:
静态代理-Static proxy
动态代理-Dynamic proxy
1. 静态代理
为实现静态代理需要为HelloSpeaker写一个HelloProxy类,同样实现IHello接口,并在hello方法执行log,并执行HelloSpeaker的hello()方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
/**
* 此处可以为接口也可以为抽象类
* @author ljn
*
*/
public
interface
IHelloSpeaker {
public
abstract
void
hello();
}
/**
* 接口实现类日志功能 简单的打印一句话
* @author ljn
*
*/
public
class
HelloSpeaker
implements
IHelloSpeaker {
public
void
hello(){
System.out.println(
"............this is Log"
);
}
}
/**
* 代理类实现IHelloSpeaker接口,同时拥有实际对象的引用(private HelloSpeaker helloObj;//代理类内部引用真实类)
* 代理必须完成委托对象的动作,也可以添加自己的动作(doBefore,doAfter)。
*
* @author ljn
*
*/
public
class
HelloProxy
implements
IHelloSpeaker {
private
HelloSpeaker helloObj;
// 代理类内部引用委托类
public
HelloProxy(HelloSpeaker helloSpeaker) {
this
.helloObj = helloSpeaker;
}
private
void
doBefore() {
System.out.println(
"method doBefore invoke!"
);
}
private
void
doAfter() {
System.out.println(
"method doAfter invoke!"
);
}
@Override
public
void
hello() {
// TODO Auto-generated method stub
doBefore();
// 其他业务逻辑
helloObj =
new
HelloSpeaker();
helloObj.hello();
// 委托类具体的业务逻辑。
doAfter();
// 其他业务逻辑
}
}
/**
*测试类
*/
public
class
Test {
public
static
void
main(String[] args) {
//其中HelloProxy中helloObject为需要代理的对象,在其它地方如下来使用代理机制
IHelloSpeaker proxy =
new
HelloProxy(
new
HelloSpeaker());
proxy.hello();
}
}
|
2:动态代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
import
java.lang.reflect.InvocationHandler;
import
java.lang.reflect.Method;
import
java.lang.reflect.Proxy;
public
class
LogHandler
implements
InvocationHandler {
private
Object delegate;
public
Object bind(Object delegate) {
this
.delegate = delegate;
return
Proxy.newProxyInstance(
delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(),
this
);
}
@Override
public
Object invoke(Object proxy, Method method, Object[] args)
throws
Throwable {
Object result =
null
;
try
{
System.out.println(
"method starts..."
+method);
result = method.invoke(delegate, args);
System.out.println(
"method starts..."
+method);
}
catch
(Exception e){
e.printStackTrace();
}
return
result;
}
}
//测试程序
public
static
void
main(String[] args) {
LogHandler logHandler =
new
LogHandler();
IHelloSpeaker helloProxy =
(IHelloSpeaker) logHandler.bind(
new
HelloSpeaker());
helloProxy.hello();
}
|