一、静态代理:代理类和目标类实现同一个接口,具备目标类的部分功能。
静态代理类优缺点
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
缺点:
1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
1.代理接口
public interface Base { //获得连接 boolean getConnection(); //查询数据 ResultSet selectSQL(String sql, Object...obj); //增删改查 int updateSQL(String sql,Object...obj); //关闭连接 void closeConnection(); }
2.委托类
public class BaseDao implements Base{ Connection connection=null; PreparedStatement pre=null; ResultSet resultSet=null; //关闭连接 public void closeConnection(){ if(resultSet!=null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if(pre!=null){ try { pre.close(); } catch (SQLException e) { e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } //连接数据库 public boolean getConnection(){ String jdbc = ConfigManager.getInstance().getInfo("jdbc"); String url = ConfigManager.getInstance().getInfo("url"); String user = ConfigManager.getInstance().getInfo("user"); String pwd = ConfigManager.getInstance().getInfo("pwd"); try { //加载驱动 Class.forName(jdbc); //获取连接 connection = DriverManager.getConnection(url, user, pwd); } catch (Exception e) { e.printStackTrace(); return false; } return true; } //查询语句 public ResultSet selectSQL(String sql,Object...obj){ // String sql="select * from student where stuname=?"; try { pre = connection.prepareStatement(sql); for(int i=0;i<obj.length;i++){ pre.setObject(i+1,obj[i]); } resultSet= pre.executeQuery(); } catch (SQLException e) { e.printStackTrace(); } return resultSet; } //增删改查 public int updateSQL(String sql,Object...obj){ int num=0; try { pre=connection.prepareStatement(sql); for(int i=0;i<obj.length;i++){ pre.setObject(i+1, obj[i]); } num= pre.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } return num; } }
3.静态代理类
public class BaseAgent implements Base{ Base base=new BaseDao(); @Override public boolean getConnection() { return base.getConnection(); } @Override public ResultSet selectSQL(String sql, Object... obj) { base.getConnection(); ResultSet resultSet = base.selectSQL(sql, obj); // base.closeConnection(); return resultSet; } @Override public int updateSQL(String sql, Object... obj) { base.getConnection(); int num=base.updateSQL(sql,obj); base.closeConnection(); return num; } @Override public void closeConnection() { base.closeConnection(); } }
4.测试类
public class TestCase { public static void main(String[] args) throws Exception{ BaseAgent ba=new BaseAgent(); String sql="select stuname from student where stuid=? or stuid=?;"; ResultSet resultSet = ba.selectSQL(sql, 2,3); while(resultSet.next()){ System.out.println(resultSet.getString("stuname")); } ba.closeConnection(); } }
二、动态代理
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
1.代理接口
public interface DoSame { void doSomething(); void say(); }
2.目标类(实现代理接口)
public class DoSameImp implements DoSame { @Override public void doSomething() { System.out.println("必须做些什么!"); } @Override public void say() { System.out.println("要说些什么?"); }
3. 实现InvocationHandler接口创建自己的调用处理器
public class DoSameHandler implements InvocationHandler { private DoSame doSame; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before========"); //利用反射机制将请求分派给委托类处理。Method的invoke返回Object对象作为方法执行结果。 Object invoke = method.invoke(doSame, args); System.out.println("after========="); return invoke; } //构造函数 public DoSameHandler(){} public DoSameHandler(DoSame doSame){ this.doSame=doSame; } }
4.测试类
public class TestCase { public static void main(String[] args) throws Exception { DoSame doSame=new DoSameImp(); // 通过 Proxy 直接创建动态代理类实例 DoSame o =(DoSame) Proxy.newProxyInstance(doSame.getClass().getClassLoader(), new Class[]{DoSame.class}, new DoSameHandler(doSame)); System.out.println("目标对象调用如下:"); doSame.doSomething(); System.out.println("代理对象调用如下:"); o.doSomething(); //打印内存中的代理类 byte[] bytes= ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{DoSame.class}); FileOutputStream fos=new FileOutputStream("$Proxy0.class"); fos.write(bytes); fos.close(); } }