Spring入门到进阶 - Spring AOP
2021-05-05 10:28
标签:cti 监视 this void single 不使用接口 连接点 tca 要求 AOP : Aspect Oriented Programing 面向切面编程 AOP采用横向抽取机制(代理机制), 取代了传统纵向继承体系重复性代码在性能监视, 事务管理, 安全检查, 缓存中使用 Spring AOP是使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码 面向切面编程,是oop(面向对象编程)的补充和完善,oop是纵向的继承结构来代表公共行为的集合,当需要引入另外一个与业务无关的松散的行为的话就很无力,比如日志系统,所有的对象系统都需要日志,以往的做法会产生大量的重复代码,耦合度提高,重用性降低,显然是不合适的。 aop用横向的代理机制将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低 模块间的耦合度,并有利于未来的可操作性和可维护性 Joinpoint(连接点):所谓连接点是指那些可以被拦截到的点。在Spring中,这些点指的是方法,因为spring只支持方法类型的连接点。 Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义;个人理解:一个要拦截或者已经被拦截的方法被称为一个切入点。 Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。个人理解:对方法进行拦截之后所做的增强方法就是通知,分为前置通知,后置通知,异常通知,最终通知,环绕通知。 Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入 Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类 Aspect(切面):是切入点和通知(引介)的结合 使用场景:对于不使用接口的业务类,无法使用JDK动态代理 CGlib采用非常底层字节码技术,可以为一个类动态的增加一些方法也可以生成一个类去继承这个类,解决无接口代理问题 Spring在运行期,生成动态代理对象,不需要特殊的编译器 Spring AOP的底层就是通过JDK动态代理或CGLib动态代理技术 为目标Bean执行横向织入 若目标对象实现了若干接口,spring使用JDK的动态代理 若目标对象没有实现任何接口,spring使用CGLIB动态代理 1、AOP联盟为通知Advice定义了org.aopalliance.aop.Interface.Adive 2、Spring按照通知Adive在目标类方法的连接点位置,可以分为5类 Advisor:一般切面(拦截目标类所有方法) 准备工作: 1、引入AOP的两个包: 2、配置目标类 开始配置: 1、编写增强类,如 2、配置到xml 3、配置增强 target:代理的目标对象 proxyInterfaces:代理要实现的接口 代码: 在测试类注入代理类: 配置代理类的相关属性: 前面的案例中,每个代理都是通过ProxyFacaoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大 解决办法:自动创建代理 BeanNameAutoProxyCreator 根据Bean名称创建代理 DefaultAdvisorAutoProxyCreator 根据Advisor本身包含信息创建代理 AnnotationAwareAspectJAutoProxyCreator 基于Bean中的AspectJ注解进行自动代理 Spring入门到进阶 - Spring AOP 标签:cti 监视 this void single 不使用接口 连接点 tca 要求 原文地址:https://www.cnblogs.com/greycdoer0/p/13192817.html
AOP概述
什么是AOP?
AOP相关术语
Target(目标对象)代理的目标对象AOP的底层原理(实现)
JDK的动态代理
public interface UserDao {
public void save();
public void update();
public void delete();
public void find();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("保存用户...");
}
public void update() {
System.out.println("修改用户...");
}
public void delete() {
System.out.println("删除用户...");
}
public void find() {
System.out.println("查询用户...");
}
}
/**
* JDK的动态代理
* 动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,实现invoke方法。
* 该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类
*/
public class MyJdkProxy implements InvocationHandler {
// 目标对象
private final UserDao userDao;
public MyJdkProxy(UserDao userDao) {
this.userDao = userDao;
}
// 绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
public Object createProxy() {
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
//根据传入的目标返回一个代理对象
return Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
}
//关联的这个实现类的方法被调用时将被执行
/*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("save".equals(method.getName())) {
System.out.println("权限校验...");
//调用目标方法
return method.invoke(userDao, args);
}
return method.invoke(userDao, args);
}
}
// 测试类
public class SpringDemo1 {
@Test
public void demo1() {
UserDao userDao = new UserDaoImpl();
UserDao proxy = (UserDao) new MyJdkProxy(userDao).createProxy();
proxy.save();
proxy.update();
proxy.delete();
proxy.find();
}
}
CGLIB的动态代理
public class ProductDao {
public void save() {System.out.println("保存商品...");}
public void update() {System.out.println("修改商品...");}
public void delete() {System.out.println("删除商品...");}
public void find() {System.out.println("查询商品...");}
}
// Cglib实现
public class MyCglibProxy implements MethodInterceptor {
private ProductDao productDao;
public MyCglibProxy(ProductDao productDao) {
this.productDao = productDao;
}
public Object createProxy() {
// 1.创建核心类
Enhancer enhancer = new Enhancer();
// 2.设置父类
enhancer.setSuperclass(productDao.getClass());
// 3.设置回调
enhancer.setCallback(this);
// 4.生成代理
Object proxy = enhancer.create();
return proxy;
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if ("save".equals(method.getName())) {
System.out.println("权限校验================");
return methodProxy.invokeSuper(proxy, args);
}
return methodProxy.invokeSuper(proxy, args);
}
}
// 测试类
public class SpringDemo2 {
@Test
public void demo1() {
ProductDao productDao = new ProductDao();
ProductDao proxy = (ProductDao) new MyCglibProxy(productDao).createProxy();
proxy.save();
proxy.update();
proxy.delete();
proxy.find();
}
}
代理知识总结
Spring的AOP的通知类型
Spring的AOP的切面
Spring的AOP的切面类型
PointcutAdvisor:代表具有切点的切面(拦截目标类指定方法)
IntroductionAdvisor:引介切面(不要求掌握)Advisor(一般切面的实现)
aopalliance
spring-aop
public class MyBeforeAdvice implements MethodBeforeAdvice {}
ProxyFactoryBean常用可配置属性
注意:如果多个接口可以使用list赋值
@Resource(name="studentDaoProxy")
private StudentDao studentDao;
public void demo1(){
studentDao.find();
}
-proxyTargetClass:是否对类代理而不是接口,设置为ture时,使用CGLib代理
-interceptorNames:需要织入目标的Advice
-singleton:返回代理是否为单实例,默认为单例
-optimize:当设置为ture时,强制使用CGLib代理PointcutAdvisor:代表具有切点的切面实现(拦截目标类指定方法)
// 目标类
public class CustomerDao {
public void find(){
System.out.println("查询客户...");
}
public void save(){
System.out.println("保存客户...");
}
public void update(){
System.out.println("修改客户...");
}
public void delete(){
System.out.println("删除客户...");
}
}
// 通知类
public class MyAroundAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("环绕前增强===================");
Object obj = invocation.proceed();
System.out.println("环绕后增强===================");
return obj;
}
}
Spring的传统AOP的动态代理
自动代理创建
基于Bean名称创建代理 (BeanNameAutoProxyCreator )
基于切面信息的自动代理 (DefaultAdvisorAutoProxyCreator)
文章标题:Spring入门到进阶 - Spring AOP
文章链接:http://soscw.com/index.php/essay/82695.html