-
什么是代理模式
代理模式也叫做委托模式,是结构性模式之一。在某些情况下,一个对象不方便或不能直接被另外一个直接引用,所以就出现了代理对象,由代理对象引用其本对象。就比如现实生活中的邮局、快递公司、婚介所等等 -
代理对象的分类
代理对象分为静态代理和动态代理
静态代理:是由程序员通过java代码创建或某些工具自动生成源代码,经过编译生成.class字节码文件,在程序运行之前就被创建好了。
动态代理:通过反射动态创建。 -
代理模式的优缺点
优点1. 降低耦合度,扩展性好 2. 保护了目标对象 3. 在原来的基础上增强了目标类
缺点
1. 增加了很多的类 2. 由于增加了增强方法,会使访问数度变慢 3. 增加了系统的复杂度(不过好的框架怎是有优缺点的,比如Spring)
-
静态代理类
我创建一个BaseService接口,这里面有eat();和toilet()这两个方法。在代理类中对这两个类进行前置和后置增强。BaseService.java
public interface BaseService {
void eat();
void toilet();
}
Person.java
public class Person implements BaseService {
public void eat() {
System.out.println("吃饭了!");
}
public void toilet() {
System.out.println("上厕所!");
}
}
PersonProxy.java
public class PersonProxy implements BaseService {
private Person person;
public PersonProxy(Person person){
this.person=person;
}
//吃饭方法
public void eat() {
before("eat");
person.eat();
after("eat");
}
//上厕所方法
public void toilet() {
before("toilet");
person.toilet();
after("toilet");
}
//前置增强
private void before(String name){
if (name.equals("toilet")){
System.out.println("记得拿纸!!!");
}else if (name.equals("eat")){
System.out.println("吃饭之前先洗手");
}
}
//后置增强
private void after(String name){
if (name.equals("toilet")){
System.out.println("记得洗手!!!");
}else if (name.equals("eat")){
System.out.println("饭后一杯茶");
}
}
}
TestMain.java
public class TestMain {
public static void main(String[] args) {
Person p=new Person();
//代理类
PersonProxy pp=new PersonProxy(p);
pp.eat();
pp.toilet();
}
}
吃饭之前先洗手
吃饭了!
饭后一杯茶
记得拿纸!!!
上厕所!
记得洗手!!!
- 动态代理
BaseService.java
public interface BaseService {
void eat();
void toilet();
}
Person.java
public class Person implements BaseService {
public void eat() {
System.out.println("吃饭了!");
}
public void toilet() {
System.out.println("上厕所!");
}
}
Invocation.java 动态代理类
public class Invocation implements InvocationHandler {
private Object obj;
public Object getInstance(Object obj){
this.obj=obj;
Class clazz=this.obj.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
//动态代理
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before(method.getName());
method.invoke(this.obj,args);
after(method.getName());
return null;
}
//前置增强
private void before(String name){
if (name.equals("toilet")){
System.out.println("记得拿纸!!!");
}else if (name.equals("eat")){
System.out.println("吃饭之前先洗手");
}
}
//后置增强
private void after(String name){
if (name.equals("toilet")){
System.out.println("记得洗手!!!");
}else if (name.equals("eat")){
System.out.println("饭后一杯茶");
}
}
}
TestMain.java
public class TestMain {
public static void main(String[] args) {
Person p=new Person();
//代理类
PersonProxy pp=new PersonProxy(p);
pp.eat();
pp.toilet();
}
}
吃饭之前先洗手
吃饭了!
饭后一杯茶
记得拿纸!!!
上厕所!
记得洗手!!!
Cglib动态代理
//引入jar包:
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
public class CglibProxy implements MethodInterceptor {
public Object getInstance(Class clazz){
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before(method.getName());
Object obj= methodProxy.invokeSuper(o,objects);
after(method.getName());
return obj;
}
private void before(String name){
if (name.equals("toilet")){
System.out.println("记得拿纸!!!");
}else if (name.equals("eat")){
System.out.println("吃饭之前先洗手");
}
}
private void after(String name){
if (name.equals("toilet")){
System.out.println("记得洗手!!!");
}else if (name.equals("eat")){
System.out.println("饭后一杯茶");
}
}
}
结果是一样的
-
JDK和CGLIB动态代理对比
1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。 2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM框架生成 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。 3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法,CGLib执行效率更高。