一: 代理模式
静态代理:代理模式
原始对象
代理对象:对原始对象的方法做了增强
动态代理
jdk的动态代理
本质:在内存中构建出接口的实现类
特点:被代理对象,必须有接口
public void jdkTest(){
//如何生成代理对象?
final UserDAO dao=new UserDAOImpl();
//1参数 :被代理对象 UserDAOImpl的类加载器
//2参数 :被代对象 所属的接口
UserDAO proxy=(UserDAO)Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), new InvocationHandler() {
/**
* proxy:代理对象
*
* method:代理对象的方法 add
*
* args:代理对象的方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("开启事务");
//真正的dao.add()
Object invoke = method.invoke(dao, args);
System.out.println("记录日志");
return invoke;
}
});
proxy.add();
}
cglib动态代理
本质:在内存中生成被代理对象的【子类】
特点:可以在没有接口的情况下代理
对于不使用接口的业务类,无法使用JDK动态代理,cglib采用非常底层的字节码技术,可以为一个类创建
子类,解决无接口代理问题
动态代理和静态代理区别??
解析:静态代理需要手工编写代理类,代理类引用被代理对象。
动态代理是在内存中构建的,不需要手动编写代理类
代理的目的:是为了在原有的方法上进行增强。
二:静态代理(具体代码)
①定义接口
//抽象主题 public interface Subject { public String request(); }
② 定义接口的实现类 RealSubject并实现该接口,重写方法--被代理对象
package cn.happy.proxy; public class RealSubject implements Subject { @Override public String request() { System.out.println("真实主题的操作内容"); return "呵呵"; } }
③定义接口的实现类ProxySubject并实现该接口重写方法。自定义属性RealSubject,调用request方法,在这里进行增强
package cn.happy.proxy; public class ProxySubject implements Subject { //01.植入一个 真实主题的引用 private RealSubject real; @Override public String request() { System.out.println("before execute"); real.request(); System.out.println("after execute"); return "proxy"; } public RealSubject getReal() { return real; } public void setReal(RealSubject real) { this.real = real; } }
④测试类
//静态代理 public class Spring_01Test { @Test public void proxyTest(){ //准备一个真实主题,被代理对象 RealSubject real=new RealSubject(); //02.创建一个代理对象 ProxySubject proxy=new ProxySubject(); proxy.setReal(real); proxy.request(); } }
执行效果:
三、动态代理
1.JDK动态代理:(具体代码)
定义接口IUserDao:
//接口 public interface IUserDAO { public String add(); public String edit(); }
定义接口实现类,实现某接口,并重写该方法:
public class UserDAOImpl implements IUserDAO { public String add() { //开启事务 System.out.println("add ok!"); return "add"; //logger } public String edit() { //开启事务 System.out.println("edit ok!"); return "edit"; //开启事务 } }
测试类:(重点)
//jdk动态代理测试 public class MyTest { @Test /** * jdk动态代理测试 */ public void staticproxyTest(){ //01.先创建出接口实现类 final IUserDAO dao=new UserDAOImpl(); //02.类Proxy IUserDAO proxy=(IUserDAO)Proxy // .newProxyInstance(dao.getClass() //获取实现类的类加载器 .getClassLoader(), dao.getClass(). // getInterfaces(), // 获取实现类接口 new InvocationHandler() { //Invocation(调用 ) Handler (处理) /**proxy 代理对象 * method 被代理对象 方法 add() * args add方法的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //code 1 System.out.println("start Tran"); //真正业务 //执行dao对象的add方法,传入的是args参数,返回值是result Object result = method.invoke(dao, args); //code 2 System.out.println("write logger"); return result; } }); String add = proxy.add(); System.out.println("======="+add+"=======");//"add" proxy.edit(); } }
实现效果:
可以看到,动态生成的代理类有如下特性:
1) 继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。
2) 提供了一个使用InvocationHandler作为参数的构造方法。
3) 生成静态代码块来初始化接口中方法的Method对象,以及Object类的equals、hashCode、toString方法。
4) 重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法。
2、cglib动态代理:(具体代码)
创建被代理的类:
public class UserService { public void delete(){ System.out.println("delete ok!"); } }
测试类:(重点)
//cglib动态代理测试 public class MyTest { @Test /** * cglib动态代理测试 */ public void cglibProxyTest(){ final UserService service=new UserService(); //cglib动态代理4 //01.需要类 Enhancer Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(service.getClass()); enhancer.setCallback(new MethodInterceptor(){ public Object intercept(Object obj, Method method, Object[] aobj, MethodProxy methodproxy) throws Throwable { System.out.println("before"); method.invoke(service, aobj); System.out.println("after"); return null; } }); //02.用方法 UserService proxy= (UserService)enhancer.create(); //03. proxy.delete(); } }
实现效果:
二:那些AOP术语
AOP Aspect Oriented Programming 面向切面编程
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
面向对象编程是从【静态角度】考虑程序的结构,而面向切面编程是从【动态角度】考虑程序运行过程。
AOP底层,就是采用【动态代理】模式实现的。采用了两种代理:JDK动态代理和CGLIB动态代理。
基本术语(一些名词):
(1)切面(Aspect)
切面泛指[*交叉业务逻辑*]。事务处理和日志处理可以理解为切面。常用的切面有通知(Advice)与顾问(Advisor)。实际就是对主业务逻辑的一种增强。
(2)织入(Weaving)
织入是指将切面代码插入到目标对象的过程。代理的invoke方法完成的工作,可以称为织入。
(3) 连接点(JoinPoint)
连接点是指可以被切面织入的方法。通常业务接口的方法均为连接点
(4)切入点(PointCut)
切入点指切面具体织入的方法
注意:被标记为final的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的。
(5)目标对象(Target)
目标对象指将要被增强的对象。即包含主业务逻辑的类的对象。
(6)通知(Advice)
通知是切面的一种实现,可以完成简单的织入功能。通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是执行之后执行等。切入点定义切入的位置,通知定义切入的时间。
(7)顾问(Advisor)
顾问是切面的另一种实现,能够将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器。
AOP代理 – 由AOP框架生成java对象。
AOP代理方法 = advice + 目标对象的方法。
下面的图简化和形象的说明了AOP