设计模式之代理模式 02


代理模式

1.代理的概念

代理模式即Proxy Pattern,23种java常用设计模式之一。代理模式的主要作用是为其他对象提供
一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,
而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式的思想是为了提供额外的处理
或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象
进行通信。代理可分为静态代理和动态代理。

2.静态代理代码实现

/**
 * 用户模块数据库操作接口
 */
public interface IUserDao {
    
    /**
     * 添加用户
     */
    public void addUser();
    
    /**
     * 删除用户
     */
    public void delUser();
}


public class UserDaoMySqlImpl implements IUserDao {


    @Override
    public void addUser() {
        System.out.println("UserDaoImpl--Mysql-addUser()");
    }


    @Override
    public void delUser() {
        System.out.println("UserDaoImpl--Mysql-delUser()");
    }
}


public class UserDaoProxyImpl implements IUserDao {


    public IUserDao userDao;
    
    public UserDaoProxyImpl(IUserDao dao){
        this.userDao = dao;
    }
    
    @Override
    public void addUser() {
        userDao.addUser();
    }


    @Override
    public void delUser() {
        userDao.delUser();
    }
}
 
/**
 * 测试Main方法
 */
public class TestMain {


    /**
     * 测试main方法
     * @param args
     */
    public static void main(String [] args){
        IUserDao dao1 = new UserDaoMySqlImpl();
 
        IUserDao dao2 = new UserDaoProxyImpl(dao1);
        dao2.addUser();
    }
}


3.动态代理实现

原理 : 使用反射对动态的去获取方法 实现 动态代理的接口
public interface HelloWorld {


    /**
     * 对外接口
     */
    public void sayHelloWorld();
}


public class HelloWorldImpl implements HelloWorld {


    /**
     * 实现类
     */
    public void sayHelloWorld() {
        System.out.println("Hello world");
    }
}


public class HelloWorldProxy implements InvocationHandler {


    /**
     * 代理对象
     */
    private Object obj;


    /**
     * 构造方法
     * @param obj
     */
    public HelloWorldProxy(Object obj){
        this.obj = obj;
    }
    
    /**
     * 默认执行方法
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result = null;
        doBefore();
        result = method.invoke(obj, args);
        doAfter();
        return result;
    }
    
    private void doBefore(){
        System.out.println("before method invoke");
    }
    
    private void doAfter(){
        System.out.println("after method invoke");
    }
    
}


public class TestMain {


    /**
     * 测试Main方法
     * @param args
     */
    public static void main(String [] args){
        HelloWorld helloWorld = new HelloWorldImpl();
        HelloWorldProxy hwp = new HelloWorldProxy(helloWorld);
        HelloWorld proxy = (HelloWorld) Proxy.newProxyInstance(helloWorld.getClass().getClassLoader(),
                helloWorld.getClass().getInterfaces(), hwp);
        proxy.sayHelloWorld();
    }
}


4.静态代理与动态代理的比较

1)静态代理由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前
  就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
2)静态代理只服务于一个接口。而动态代理可以服务于多个接口。例如上述代码中的静态代理实现
  的是IUserDao接口,该代理类只服务于该接口,而动态代理HelloWorldProxy实现的是
  InvocationHandler接口,其不仅仅可以为 HelloWorld接口服务,也可为其他新增接口服务。
3)静态代理中如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要
  实现此方法。增加了代码维护的复杂度。
4)动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的
  字节码文件。代理类和委托类的关系是在程序运行时确定。动态代理中的ClassLoader是类装载器类,
  负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy 
  静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是
  其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。 每次生成动态代理类
  对象时都需要指定一个类装载器对象.
5)动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中
  处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理
  那样每一个方法进行中转。


5.简单Spring 切面编程实现

注解 + 动态代理 实现
1.创建注解类Get 
2.创建注解类After
3.创建动态代理类
测试:
4.创建接口
5.实现接口类
6.切面类
7.测试
package spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 如果某类中声明了该注释  表示使用切面编程
 * @author 李昂志
 */
@Retention(RetentionPolicy.RUNTIME) //运行时调用
@Target(value = {ElementType.TYPE }) //只允许生命在类前面
public @interface Get {
	String classpath();
}

package spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 在类的方法后执行该方法
 * @author 李昂志
 *
 */
@Retention(RetentionPolicy.RUNTIME) //运行时调用
@Target(value = {ElementType.METHOD}) //只允许声明在方法前面
public @interface After {
	String methodName();//要加载
}
package spring;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * 代理类  动态实现切面编程
 * @author 李昂志
 *
 */
public class ProxySpring implements InvocationHandler {
	private Object obj;
	public ProxySpring(Object obj){
		this.obj = obj;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Get get = obj.getClass().getAnnotation(Get.class);
		Object result = null;
		result  = method.invoke(this.obj, args);
		if(get != null){
			get.classpath();
			Class c = Class.forName(get.classpath());
			Method[] ms =  c.getMethods();
			for(Method m : ms ){
				After a = m.getAnnotation(After.class);
				if(a != null) {
					m.invoke(c.newInstance());
				}
			}
		}
		return result;
	}

}

package spring;

import java.lang.reflect.Proxy;

/**
 * 测试类
 * @author 李昂志
 */
@Get(classpath = "spring.Aop")
public class TestSpring implements A{
	@Override
	public void say() {
		// TODO Auto-generated method stub
		System.out.println("I'm say hello world");
	}
	public static void main(String[] args) {
		A a = new TestSpring();
		ProxySpring ps = new ProxySpring(a);
		A b = (A)Proxy.newProxyInstance(a.getClass().getClassLoader(), a.getClass().getInterfaces(), ps);
		b.say();
	}
}
/**
 * 接口
 * @author 李昂志
 */
interface A{
	public void say();
}
/**
 * 切面类  
 * @author 李昂志
 */
class Aop{
	//切面方法
	@After(methodName = "nothind to do")
	public void after(){
		System.out.println(" 我是 aop  after 方法");
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值