在了解aop之前有必要先知道两个知识
静态代理和动态代理
静态代理某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。
代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。
代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
代码实现
接口
public interface Marry {
// 结婚
void toMarry();
}
被代理对象
public class you implements Marry {
@Override
public void toMarry() {
System.out.println("我要结婚了");
}
}
代理对象
public class MarryCompanyProxy implements Marry {
//多态的方式
private Marry marry;
//提供一个有参构造 创建该对象的时候必须传入一个Marry的实现类
public MarryCompanyProxy(Marry marry) {
this.marry = marry;
}
@Override
public void toMarry() {
before();
//原来的你
marry.toMarry();
after();
}
private void after() {
System.out.println("结婚前的布置");
}
private void before() {
System.out.println("结婚后的收场");
}
}
测试类
public class StaticProxy {
public static void main(String[] args) {
//目标对象
you you = new you();
//代理对象
MarryCompanyProxy marryCompanyProxy = new MarryCompanyProxy(you);
//通过代理对象调目标对象中的方法
marryCompanyProxy.toMarry();
}
}
运行结果
通过代理我们可以在不改变被代理对象代码的基础上添加新功能
但是有一个问题,我要是有很多个需要被代理的对象呢?我们要分别创建对应的代理对象
这样子太不灵活了
静态代理的特点1.目标角色固定
2在应用程序之前就得知目标角色
3.代理对象会增强目标对象的行为
4.有可能存在多个代理,产生类爆炸"(缺点)
动态代理相比于静态代理,动态代理在创建代理对象上更加的灵活,动态代理类的字节码在程序运行时,
由lava反射机制动态产生。它会根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象,
无需程序员手动编写它的源代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,
因为反射机制可以生成任意类型的动态代理类。代理的行为可以代理多个方法
即满足生产需要的同时又达到代码通用的目的
动态代理呢又分为两种
一种是JDK动态代理和cglib代理,我们来分别演示
JDK动态代理
public interface Marry {
// 结婚
void toMarry();
}
public class you implements Marry {
@Override
public void toMarry() {
System.out.println("我要结婚了");
}
}
public class JdkHandler implements InvocationHandler {
//目标对象
private Object target;//目标对象的类型不固定,创建时动态生成
//通过有参构造传递目标对象
public JdkHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强前
System.out.println("增强前");
//调用目标对象的方法
Object object = method.invoke(target, args);
//增强后
System.out.println("增强后");
return object;
}
public Object getProxy(){
Object object = Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
return object;
}
}
public class JdkHandlerText {
public static void main(String[] args) {
//目标对象
you you = new you();
//目标对象的代理类
JdkHandler jdkHandler = new JdkHandler(you);
//得到代理对象
Marry marry = (Marry) jdkHandler.getProxy();
marry.toMarry();
}
}
运行结果
通过观察我们发现这种动态代理还是非常灵活的,
不管什么类型的对象都能被代理
但是但是!
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能使用JDK的动态代理,
cglib是针对类来实现代理的,它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,
但因为采用的是继承,所以不能对final修饰的类进行代理。
cglib代理下面来介绍cglib代理
首先要导入依赖
cglib cglib2.2.2
public interface Marry {
// 结婚
void toMarry();
}
public class you implements Marry {
@Override
public void toMarry() {
System.out.println("我要结婚了");
}
}
public class CglibInterceptor implements MethodInterceptor {
//目标对象
private Object target;
//通过构造器传入代理对象
public CglibInterceptor(Object target) {
this.target = target;
}
public Object getProxy(){
//通过 Enhancer对象中的create()方法生成一个类,用于生成代理对象
Enhancer enhancer = new Enhancer();
//设置父类(将目标类作为代理类的父类)
enhancer.setSuperclass(target.getClass());
//设置拦截器,回调对象为本身对象(参数是这个Callback 我们实现的这个类继承了Callback,所以传this)
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("方法的增强行为");
//调用目标类的方法
Object obj = method.invoke(target, objects);
System.out.println("方法的增强行为");
return obj;
}
}
//测试
public class CglibInterceptortest {
public static void main(String[] args) {
you you = new you();
//得到拦截器
CglibInterceptor cglibInterceptor = new CglibInterceptor(you);
//得到代理对象
Marry marry = (Marry) cglibInterceptor.getProxy();
marry.toMarry();
}
}
cglib代理不依赖于接口 ,不依赖与共同的行为,所以即使传过来一个任意类都是可以实现代理的
两种动态代理的区别两种动态代理的区别:
Jdk动态代理实现接口,cglib动态代理是继承思想,继承然后重写
JDk动态代理(目标对象存在接口时)执行效率高于cglib
如果目标对象有接口实现,选择JDK代理,如果没有,选择cglib代理
了解了这两种代理,我们来学习springAop其实是非常简单的
Aop的底层就是JDk动态代理+cglib
SpringAop 什么是AOP?Aspect Oriented Programing面向切面编程,相比较oop面向对象编程来说,Aop关注的不再是程序代码中某个类,某些方法,而aop考虑的更多的是一种面到面的切入,即层与层之间的一种切入,所以称之为切面。联想大家吃的汉堡(中间夹肉)。那么aop是怎么做到拦截整个面的功能呢?考虑前面学到的servletfilter @Service public class UserServiceImpl { public void save(){ System.out.println("userservice..."); } }
然后要定义一个切面类
@Component//将对象交给ioc进行实例化
public class LogCut02 {
public void cut() {
}
public void before() {
System.out.println("前置通知");
}
public void afterReturn() {
System.out.println("返回通知");
}
public void after() {
System.out.println("最终通知");
}
public void afterThrow(Exception e) {
System.out.println("异常通知"+e.getMessage());//异常原因
}
public Object around(ProceedingJoinPoint pjp) {
System.out.println("环绕通知-前置通知");
try {
//显示调用对应的方法
Object proceed = pjp.proceed();
System.out.println("环绕通知中的返回通知");
} catch (Throwable e) {
e.printStackTrace();
System.out.println("环绕通知的异常通知");
}
System.out.println("环绕通知-最终通知");
return new Object();
}
}
然后我们在xml文件中进行配置切面
编写测试类
public class app {
public static void main(String[] args) {
//获取上下文环境
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
//通过类型获取bean
// UserServiceImpl service = (UserServiceImpl) context.getBean(UserServiceImpl.class);
//通过名称获取,这个名字是默认第一位字母小写
UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("userServiceImpl");
serviceImpl.save();
}
}
执行结果:
注解实现AOP
我们重新创建一个切面类
之前xml文件中配置的切面通通可以删除掉
上代码
@Component//将对象交给ioc进行实例化
@Aspect//声明当前是一个切面
public class LogCut {
@Pointcut("execution(* com.ithcast.Service..*.*(..))")
public void cut() {
}
@Before("cut()")
public void before() {
System.out.println("前置通知");
}
@AfterReturning("cut()")
public void afterReturn() {
System.out.println("返回通知");
}
@After("cut()")
public void after() {
System.out.println("最终通知");
}
@AfterThrowing(value = "cut()",throwing = "e")
public void afterThrow(Exception e) {
System.out.println("异常通知"+e.getMessage());//异常原因
}
@Around("cut()")
public Object around(ProceedingJoinPoint pjp) {
System.out.println("环绕通知-前置通知");
try {
//显示调用对应的方法
Object proceed = pjp.proceed();
System.out.println(pjp.getTarget());
System.out.println("环绕通知中的返回通知");
} catch (Throwable e) {
e.printStackTrace();
System.out.println("环绕通知的异常通知");
}
System.out.println("环绕通知-最终通知");
return new Object();
}
}
运行结果
注解开发还是非常方便的,也是眼下企业的主流
SpringAOP总结代理模式实现三要素
1.接口定义
2.目标对象与代理对象必须实现统一接口
3.代理对象持有目标对象的引用增强目标对象行为
代理模式实现分类以及对应区别
1.静态代理:手动为目标对象制作代理对象,即在程序编译阶段完成代理对象的创建
2.动态代理:在程序运行期动态创建目标对象对应代理对象。
3.idk动态代理:被代理目标对象必须实现某一或某一组接口实现方式通过回调创建代理对象。
4.cglib动态代理:被代理目标对象可以不必实现接口,继承的方式实现。
动态代理相比较静态代理,提高开发效率,可以批量化创建代理,提高代码复用率。
Aop 理解
1.面向切面,相比oop关注的是代码中的层或面
2.解耦,提高系统扩展性3提高代码复用
Aop 关键词
1.连接点每一个方法
2.切入点:匹配的方法集合
3.切面:连接点与切入点的集合决定了切面,横切关注点的抽象
4.通知:几种通知
5.目标对象被代理对象
6.织入:程序运行期将切面应用到目标对象并生成代理对象的过程
7.引入:在不修改原始代码情况下,在程序运行期为程序动态引入方法或字段的过程



