Spring AOP笔记:
应用场景: 日志记录,异常的统一处理,权限验证,事务处理。
什么是叫做面向切面编程。
Aop是什么?-----------编程需要实现的目标,实现面向切面编程
SpringAOP是什么?-----实现这个目标的手段
AOP的两种实现形式:
-
SpringAOP
-
Aspectj
切面(Aspect):
其实就是共有功能的实现。如日志切面、权限切面、事务切面等。在实际应用中通常是一个存放共有功能实现的普通Java类,之所以能被AOP容器识别成切面,是在配置中指定的。
在自上而下的执行的业务逻辑过程中,会产生一些横切性的问题,比如说日志记录,异常的统一处理,权限验证,事务处理等,与主业务逻辑没有直接的关系
面向切面的思想就是把这些横切性的问题模块化成为一个切面,程序员只需关注切面的执行顺序,执行时机即可。
Java动态代理(代理模式/委托模式)
1、代理的定义
为其他对象提供一种代理以控制对这个对象的访问。
代理模式
代理模式是面向对象编程中比较常见的设计模式
代理模式( Proxy Pattern ):
一个类代表另一个类的功能,一般用于对要访问的类做一些控制、功能增强,同时又不想影响原来类的正常业务;
需要注意的有下面几点:
用户只关心接口功能,而不在乎谁提供了功能。上图中接口是 Subject。
接口真正实现者是上图的 RealSubject,但是它不与用户直接接触,而是通过代理。
代理就是上图中的 Proxy,由于它实现了 Subject 接口,所以它能够直接与用户接触。
用户调用 Proxy 的时候,Proxy 内部调用了 RealSubject。所以,Proxy 是中介者,它可以增强 RealSubject 操作
。
现在可以看到,
代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。
值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。
Java动态代理(代理模式/委托模式)
1、代理的定义
为其他对象提供一种代理以控制对这个对象的访问。
![](https://i-blog.csdnimg.cn/blog_migrate/2cc82985fa116a00691ca57aa3e2073f.png)
代理模式
代理模式是面向对象编程中比较常见的设计模式。
![](https://i-blog.csdnimg.cn/blog_migrate/2e9c66ff78a71a991961181c5becdffa.png)
代理模式( Proxy Pattern ):
一个类代表另一个类的功能,一般用于对要访问的类做一些控制、功能增强,同时又不想影响原来类的正常业务;
需要注意的有下面几点:
用户只关心接口功能,而不在乎谁提供了功能。上图中接口是 Subject。
接口真正实现者是上图的 RealSubject,但是它不与用户直接接触,而是通过代理。
代理就是上图中的 Proxy,由于它实现了 Subject 接口,所以它能够直接与用户接触。
用户调用 Proxy 的时候,Proxy 内部调用了 RealSubject。所以,Proxy 是中介者,它可以增强 RealSubject 操作
。
现在可以看到,
代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。
值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。
2、代理的使用场景
在某些情况下,我们不希望或是不能直接访问对象 A,而是通过访问一个中介对象 B,由 B 去访问 A 达成目的,这种方式我们就称为代理。
这里对象 A 所属类我们称为委托类,也称为被代理类,对象 B 所属类称为代理类。
代理优点有:
-
隐藏委托类的实现
-
解耦,不改变委托类代码情况下做一些额外处理,比如添加初始判断及其他公共操作
根据程序运行前代理类是否已经存在,可以将代理分为静态代理和动态代理。
3)静态代理和动态代理
动态代理静态代理的区别,代理涉及到两个关联词代理类和委托类。静态代理一个代理类针对一个委托类!动态代理一个代理类可利用反射机制代理多个委托类
eg:经纪人是代理类,明星是委托类。静态代理是经纪人A服务一个明星,而动态代理是经纪人A服务多个明星。
我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制,在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。
(4)静态代理
![](https://i-blog.csdnimg.cn/blog_migrate/d7799c0d3471515fa572d691ba9d3108.png)
优点:可以实现不对目标对象进行修改的前提下,对目标对象进行功能的扩展和增强,也就是扩展原功能, 不污染原代码。
缺点:因为代理对象,需要实现与目标对象一样的接口,如果目标接口类繁多也会导致代理类繁多,同时一旦接口增加方法,则目标对象和代理类都需要维护。
我们先创建一个接口,
遗憾的是java api代理机制求被代理类必须要实现某个接口,对于静态代理方式代理类也要实现和被代理类相同的接口
;对于动态代理代理类则不需要显示的实现被代理类所实现的接口。
1.创建一个代理类和委托类的公有父级接口
package com.ztb.staticDL;
public interface TargetClass {
void sayHello();
}
2.创建一个委托类(也就是目标类)
package com.ztb.staticDL;
public class TargetImpl implements TargetClass {
@Override
public void sayHello() {
System.out.println("静态代理,打印SayHello方法");
}
}
3.创建代理类(代理类是为了加强目标类的功能)
package com.ztb.staticDL;
public class ProxyClass implements TargetClass{
private TargetImpl target;//持有一个代理目标对象的引用
//eg:让黄牛代理买票你得让黄牛知道你的个人信息
public ProxyClass(TargetImpl target) {
this.target = target;//目标类也就是代理类需要初始化一下。不然会报空指针异常
}
@Override
public void sayHello() {
//调用目标类的方法,同时可以增强目标类的方法
System.out.println("代理方法前");
target.sayHello();//
System.out.println("代理方法后");
}
}
3.测试(用户调用)
package com.ztb.staticDL;
import com.sun.xml.internal.bind.v2.util.StackRecorder;
public class Client {
public static void main(String[] args) {
// TargetImpl target=new TargetImpl();
// target.sayHello();//传统方法调用目标对象的方法
ProxyClass proxyClass=new ProxyClass(new TargetImpl());
proxyClass.sayHello();//通过代理类调用目标对象的方法
}
}
4.测试结果截图
(5)动态代理(三要素:目标接口,目标接口实现,实现 InvocationHandler的类)
1、代理对象是由谁产生的?
jvm产生的,不像上次的静态代理,我们自己得new个代理对象出来。
2、代理对象实现了什么接口?
实现的接口是目标对象实现的接口。同静态代理模式中代理对象实现的接口。那个继承关系图还是相同的。代理对象和目标对象都实现一个共同的接口。就是这个接口。所以Proxy.newProxyInstance()方法返回的类型就是这个接口类型。
3、代理对象的方法体是什么?
代理对象的方法体中的内容就是拦截器中invoke方法中的内容
。所有代理对象的处理逻辑,控制是否执行目标对象的目标方法。都是在这个方法里面处理的。
4、拦截器中的invoke方法中的method参数是在什么时候赋值的?
在客户端,代理对象调用目标方法的时候,此实例中为:proxyObj.business();
实际上进入的是拦截器中的invoke方法,这个时候
,拦截器中的invoke方法中的method参数会被赋值。
最后,为啥这个方式叫做jdk动态代理呢?
因为这个动态代理对象时用jdk的相关代码生成的,所以这个叫jdk动态代理。
后面的cglib动态代理,就是因为要用到cglib的jar包,所以才叫cglib动态代理。
简易实现动态代理的例子:
1.先给出接口
package com.ztb.dynamicProxy;
public interface TargetClass {
void sayHello();
}
2.定义委托类(也就是目标类),实现接口
package com.ztb.dynamicProxy;
public class TargetImpl implements TargetClass {
@Override
public void sayHello() {
System.out.println("动态代理,打印SayHello方法");
}
}
3..定义协助实现代理类的辅助类
package com.ztb.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* ProxyClass这个类不是代理类,而是辅助真正的代理类去工作。。
* 是动态代理的一部分
*/
public class ProxyClass implements InvocationHandler {
private Object target;//传入目标对象引用
public ProxyClass(Object target) {
this.target = target;
}
/**
* 在调用目标类的sayHello()方法时,会先调用invoke()方法。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
System.out.println("目标方法执行前。。。。。。");
Object result=method.invoke(target,args);//在这里真正调用sayHello()方法
//result 是目标方法的返回值
System.out.println("目标方法执行后。。。。。。");
return result;
}
}
4.编写测试类
package com.ztb.dynamicProxy;
import java.lang.reflect.Proxy;
public class Client2 {
public static void main(String[] args) {
//
// TargetImpl target=new TargetImpl();
// target.sayHello();
/**
** targetClass才是正真的代理类.通过Proxy.newProxyInstance()方法强转得到的。
*/
TargetClass targetClass= (TargetClass)Proxy.newProxyInstance(TargetClass.class.getClassLoader(),
new Class[] {TargetClass.class},new ProxyClass(new TargetImpl()) );
targetClass.sayHello();
}
}
5.运行结果。
动态代理语法
放轻松,下面我们开始讲解语法,语法非常简单。
动态代码涉及了一个非常重要的类 Proxy。正是通过 Proxy 的静态方法 newProxyInstance 才会动态创建代理。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
loader 自然是类加载器
interfaces 代码要用来代理的接口
h 一个 InvocationHandler 对象
InvocationHandler
InvocationHandler 是一个接口
,官方文档解释说,每个代理的实例都有一个与之关联的 InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
InvocationHandler 内部只是一个 invoke() 方法,正是这个方法决定了怎么样处理代理传递过来的方法调用。
proxy 代理对象
method 代理对象调用的方法
args 调用的方法中的参数
总结:
代理分为静态代理和动态代理两种。
静态代理,代理类需要自己编写代码写成。
动态代理,代理类通过 Proxy.newInstance() 方法生成
。
不管是静态代理还是动态代理,代理与被代理者都要实现两样接口,它们的实质是面向接口编程。
静态代理和动态代理的区别是在于要不要开发者自己定义 Proxy 类。
动态代理通过 Proxy 动态生成 proxy class,但是它也指定了一个 InvocationHandler 的实现类。
代理模式本质上的目的是为了增强现有代码的功能。