miracle just wanna be better

代理设计模式

2019-11-01
miracle

spring的aop,mybatis的mapper写法

静态代理

在程序运行之前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了.

  1. 定义抽象接口
public interface HouseSubject {
	public void rentHouse();
}
  1. 定义具体对象
public class RealHouseSubject implements HouseSubject{
	@Override
	public void rentHouse() {
		System.out.println("我是主人我要出租房子");	
	}
}
  1. 代理
public class HouseProxy implements HouseSubject{
	@Override
	public void rentHouse() {
		this.ad();
		RealHouseSubject rhs=new RealHouseSubject();
		rhs.rentHouse();
		this.backAd();
	}
	private void ad(){
		System.out.println("广告,出租房屋");
	}
	private void backAd(){
		System.out.println("已出租");
	}
}
  1. 测试
public class User {
	public static void main(String[] args) {
		HouseProxy proxy=new HouseProxy();
		proxy.rentHouse();
	}
}

动态代理

  1. 为什么要用动态代理

静态代理接口每增加一个方法,实现类需要实现一个方法.增加了代码维护复杂度. 静态代理方式需要为每一个类(客户)增加一个代理类(中介)

  1. 定义抽象接口类
public interface HouseSubject {
	public void rentHouse();
}
  1. 定义具体对象
public class RealHouseSubjectA implements HouseSubject{
	@Override
	public void rentHouse() {
		System.out.println("我是主人A,我要出租房子");
	}
}
public class RealHouseSubjectB implements HouseSubject{
	@Override
	public void rentHouse() {
		System.out.println("我是主人B,我要出租房子");
	}
}
  1. 定义代理类
public class DynamicProxy implements InvocationHandler{
	private Object proxyObject;
	public Object newProxyInstance(Object proxyObject){
		this.proxyObject=proxyObject;
		//生成动态代理类实例
		return Proxy.newProxyInstance(
				//指定产生代理对象的类加载器
				proxyObject.getClass().getClassLoader(),
				//指定目标对象的实现接口
				proxyObject.getClass().getInterfaces(),
				//指定InvocationHandler对象
				this
				);
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("我是动态代理类,我要出租房子");
		Object result=method.invoke(proxyObject, args);
		System.out.println("房子以租出");
		return result;		
	}
}
  1. 测试类
public class User {
	public static void main(String[] args) {
		// 创建一个动态代理类
		DynamicProxy dynamicProxy = new DynamicProxy();
		// 创建两个目标对象
		RealHouseSubjectA a = new RealHouseSubjectA();
		RealHouseSubjectB b = new RealHouseSubjectB();
		// 动态代理拿到相应的操作权限
		HouseSubject houseAproxy = (HouseSubject) dynamicProxy.newProxyInstance(a);
		HouseSubject houseAproxy2 = (HouseSubject) dynamicProxy.newProxyInstance(b);
		houseAproxy.rentHouse();
		houseAproxy2.rentHouse();
	}
}

区别

静态代理在代码运行前就与对象绑定,只能代理单一对象
动态代理在运行时才与对象绑定,可以代理多个目标对象

代理模式的缺点

  1. 处理速度慢,有些代理较为复杂

代理模式的使用场景

  1. 当需要访问远程主机对象时,使用远程代理
  2. 当需要一个消耗资源较少的对象代表一个消耗资源较多的对象可以使用虚拟代理
  3. 频繁操作一个对象,为其设置缓冲器时可以使用缓冲代理
  4. 不同的对象提供访问权限时可以使用保护代理
  5. 当需要为一个对象的访问提供一些额外的操作时可以使用智能引用代理

mybatis

mybatis原生代码,Sqlsession对象打点使用相应的方法

public class TestUserClass {
	private SqlSessionFactory sqlSessionFactory;
	@Before 
	public void beforeMethod(){
		String resource = "conf/configuration.xml";
		try {
			InputStream inputStream = Resources.getResourceAsStream(resource);
			 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	@Test
	public void testFindUserById(){
		//Session可以理解成jdbc的Connection
		SqlSession sqlSession=null;
		try{
			sqlSession=this.sqlSessionFactory.openSession();
			User user=sqlSession.selectOne("cn.tedu.xxx.yyy.findUserById",3);
			System.out.println(user);
			sqlSession.commit();
		}catch(Exception e){
			sqlSession.rollback();
			e.printStackTrace();
		}finally{
			sqlSession.close();
		}
	}
	
	@Test
	public void testFindUserByPage1_1(){
		//Session可以理解成jdbc的Connection
		SqlSession sqlSession=null;
		try{
			sqlSession=this.sqlSessionFactory.openSession();
			Page page=new Page();
			page.setCurrentPage(1);
			page.setUserAddressKeyword("%昌%");
			page.setUserNameKeyword("%c%");
			page.setPageSize(3);
			List<User> users=sqlSession.selectList("findUserByPage1",page);
			for(User user:users){
				System.out.println(user);
			}
			
			sqlSession.commit();
		}catch(Exception e){
			sqlSession.rollback();
			e.printStackTrace();
		}finally{
			sqlSession.close();
		}
	}

用mybatis的mapper接口的方式的api做增删改查操作

用代理对象调用目标方法,事实上执行的是InvocationHanler接口的invoke方法
在invoke方法中根据Method得到的方法的名称,根据xml中获取的parameterType和resultType来决定调用mybatis原生的api方法

public class TestUserClass {
	private SqlSessionFactory sqlSessionFactory;
	@Before 
	public void beforeMethod(){
		String resource = "conf/configuration.xml";
		try {
			InputStream inputStream = Resources.getResourceAsStream(resource);
			 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	@Test
	public void testFindUserById(){
		SqlSession sqlSession=null;
		try{
			sqlSession=this.sqlSessionFactory.openSession();
			//userMapper对象是一个jdk的动态代理对象
			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
			//用代理对象调用目标方法,事实上执行的是InvocationHanler接口的invoke方法
			//在invoke方法中根据Method得到的方法的名称,根据xml中获取的parameterType和resultType来决定调用mybatis原生的api方法
			User user=userMapper.findUserById(1);
			System.out.println(user);
			sqlSession.commit();
		}catch(Exception e){
			sqlSession.rollback();
			e.printStackTrace();
		}finally{
			sqlSession.close();
		}
	}

上一篇 final关键字

下一篇 序列化

Comments

Content