一、什么是AOP

  aspect-oriented  programming,面向切面编程,对oop的一种补充。

  著名示例,aspectj,spring+aspectj

二、aop之代码重构

2.1、代理重构

示例代码

public interface Greeting {
void sayHello(String name);
}

实现

public class GreetingImpl implements Greeting {
@Override
public void sayHello(String name) {
before();
System.out.println("hello " + name);
after();
} private void before() {
System.out.println("before");
} private void after() {
System.out.println("after");
}
}

以上便是标准的死代码,不宜扩展。

代码重构:

1、静态代理

2、JDK动态代理

3、CGLib动态代理

2.1.1、静态代理

实现

package com.lhx.chapter4.aop.staticproxy;

import com.lhx.chapter4.aop.Greeting;
import com.lhx.chapter4.aop.GreetingImpl; public class GreetingProxy implements Greeting {
private GreetingImpl greetingImpl;
public GreetingProxy(GreetingImpl greetingImpl){
this.greetingImpl=greetingImpl;
} @Override
public void sayHello(String name) {
before();
greetingImpl.sayHello(name);
after();
} private void before() {
System.out.println("before");
} private void after() {
System.out.println("after");
}
}

调用

package com.lhx.chapter4.aop.staticproxy;

import com.lhx.chapter4.aop.Greeting;
import com.lhx.chapter4.aop.GreetingImpl; public class Client {
public static void main(String[] args) {
Greeting proxy = new GreetingProxy(new GreetingImpl());
proxy.sayHello("木子旭");
}
}

会导致XxxProxy越来越多。

2.1.2、JDK动态代理

实现

package com.lhx.chapter4.aop.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class JDKDynamicProxy implements InvocationHandler {
private Object target; public JDKDynamicProxy(Object target) {
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
} public <T> T getProxy() {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
} private void before() {
System.out.println("Before");
} private void after() {
System.out.println("After");
}
}

调用

package com.lhx.chapter4.aop.dynamicproxy;

import com.lhx.chapter4.aop.Greeting;
import com.lhx.chapter4.aop.GreetingImpl; public class JDKDynamicProxyClient {
public static void main(String[] args) {
JDKDynamicProxy dynamicProxy = new JDKDynamicProxy(new GreetingImpl());
Greeting proxy = dynamicProxy.getProxy();
proxy.sayHello("muzixu");
}
}

所有的动态代理都合并到代理类了,JDK动态代理只能代理接口,不能代理没有接口的类。

2.1.3、CGLib动态代理

实现

package com.lhx.chapter4.aop.dynamicproxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CGLibDynamicProxy implements MethodInterceptor {
private static CGLibDynamicProxy instance = new CGLibDynamicProxy();
private CGLibDynamicProxy(){
}
public static CGLibDynamicProxy getInstance(){
return instance;
}
public <T> T getProxy(Class<T> cls) {
return (T) Enhancer.create(cls,this);
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object result = methodProxy.invokeSuper(o,objects);
after();
return result;
}
private void before() {
System.out.println("Before");
} private void after() {
System.out.println("After");
}
}

调用

package com.lhx.chapter4.aop.dynamicproxy;

import com.lhx.chapter4.aop.Greeting;
import com.lhx.chapter4.aop.GreetingImpl; public class CGLibDynamicProxyClient {
public static void main(String[] args) {
Greeting proxy = CGLibDynamicProxy.getInstance().getProxy(GreetingImpl.class);
proxy.sayHello("muzixu");
}
}

2.2、spring aop

1、spring aop(编程式):before advice 前置增强【通知】、after advice 后置增强【通知】、Around advice环绕增强【通知,前两种的结合】

  可以理解为增强类

前置增强

package com.lhx.chapter4.aop.springaop;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class GreetingBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("Before");
}
}

后置增强

package com.lhx.chapter4.aop.springaop;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class GreetingAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("after");
}
}

调用

package com.lhx.chapter4.aop.springaop;

import com.lhx.chapter4.aop.GreetingImpl;
import org.springframework.aop.framework.ProxyFactory; public class GreetingAdviceClient {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();//创建代理工厂
proxyFactory.setTarget(new GreetingImpl());//射入目标类对象
proxyFactory.addAdvice(new GreetingBeforeAdvice());//前置通知
proxyFactory.addAdvice(new GreetingAfterAdvice());//后置
//proxyFactory.addAdvice(new GreetingBeforeAndAfterAdvice());//前后结合
proxyFactory.addAdvice(new GreetingAroundAdvice());//环绕 GreetingImpl greeting = (GreetingImpl) proxyFactory.getProxy();
greeting.sayHello("木子旭");
}
}

前置后置合并一个

package com.lhx.chapter4.aop.springaop;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class GreetingBeforeAndAfterAdvice implements MethodBeforeAdvice, AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("After");
} @Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("Before");
}
}

环绕通知

package com.lhx.chapter4.aop.springaop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.stereotype.Component; @Component
public class GreetingAroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
before();
Object proceed = methodInvocation.proceed();
after();
return proceed;
}
private void before(){
System.out.println("Before");
}
private void after(){
System.out.println("after");
}
}

  环绕通知不是spring提供是由org.aopalliance.intercept.MethodInterceptor提供

2、spring aop(声明式):before advice 前置增强【通知】、after advice 后置增强【通知】、Around advice环绕增强【通知,前两种的结合】

spring的application-aop.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描指定包(将带有Compontent注解的类自动定义为Spring bean)-->
<context:component-scan base-package="com.lhx.chapter4.aop"></context:component-scan>
<!--配置一个代理-->
<bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--需要代理的接口-->
<property name="interfaces" value="com.lhx.chapter4.aop.Greeting"></property>
<!--接口实现类-->
<property name="target" ref="greetingImpl"></property>
<!--拦截器名称(也是增强类名称,Spring Bean的id)-->
<property name="interceptorNames">
<list>
<value>greetingAroundAdvice</value>
</list>
</property>
</bean>
</beans>

  ProxyFactoryBean相当于ProxyFactory

在部分实现类增加@Component注解

客户端调用

package com.lhx.chapter4.aop.springaopdeclare;

import com.lhx.chapter4.aop.Greeting;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client {
public static void main(String[] args) {
//获取spring content
ApplicationContext context =new ClassPathXmlApplicationContext("application-aop.xml");
//从Content中根据id获取Bean对象,其实就是一个代理
Greeting greetingProxy = (Greeting) context.getBean("greetingProxy");
greetingProxy.sayHello("muzixu "); }
}

3、Spring AOP:Throws Advice【抛出增强】

  程序报错,抛出异常,一般做法打印到控制台或者日志文件。一劳永逸办法使用,Throws Advice

异常接口

package com.lhx.chapter4.aop;

public interface Greeting {
void sayHello(String name);
void sayHelloThrows(String name);
}

抛出异常增强类

package com.lhx.chapter4.aop.springaopthrows;

import org.springframework.aop.ThrowsAdvice;

import java.lang.reflect.Method;

public class GreetingThrowsAdvice implements ThrowsAdvice {
//public void afterThrowing(Exception ex)
//public void afterThrowing(RemoteException)
//public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
//public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex){
System.out.println("--------Throw Exception-------");
System.out.println("Target class:"+target.getClass().getName());
System.out.println("Method name:"+method.getName());
System.out.println("Exception:"+ex.getMessage());
System.out.println("------------------------------"); }
}

  接口中没有任何抽象方法,但是自定义又会出异常,Spirng内部是用反射来实现方法匹配的,需要实现下列接口中的其中1个

    //public void afterThrowing(Exception ex)
//public void afterThrowing(RemoteException)
//public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
//public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)

4、Spring AOP:Introduction Advice【引入增强】

  在AOP中对方法的增强叫Weaving【织入】,对类的增强叫Introduction【引用】,Introduction advice【引用增强】就是对类功能的增强。

  示例:类C实现了A接口,那么使类C可以调用B接口

新增一个接口

package com.lhx.chapter4.aop.springaopintroductionadvice;

public interface Apology {
void saySorry(String name);
}

不想改变原有类的实现,需要使用引用增强

package com.lhx.chapter4.aop.springaopintroductionadvice;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor; public class GreetingIntroductionAdvice extends DelegatingIntroductionInterceptor implements Apology {
@Override
public void saySorry(String name) {
System.out.println("sorry " + name);
} @Override
public Object invoke(MethodInvocation mi) throws Throwable {
return super.invoke(mi);
}
}

  引用增强类扩展了org.springframework.aop.support.DelegatingIntroductionInterceptor,同时实现了需要的接口

需要的Spring配置application-aop-intro.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描指定包(将带有Compontent注解的类自动定义为Spring bean)-->
<context:component-scan base-package="com.lhx.chapter4.aop"></context:component-scan>
<!--配置一个代理-->
<bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--需要代理的接口-->
<property name="interfaces" value="com.lhx.chapter4.aop.springaopintroductionadvice.Apology"></property>
<!--接口实现类-->
<property name="target" ref="greetingImpl"></property>
<!--拦截器名称(也是增强类名称,Spring Bean的id)-->
<property name="interceptorNames" value="greetingIntroductionAdvice"> </property>
<!--代理目标 false 接口 true 类 默认是false-->
<property name="proxyTargetClass" value="true"></property>
</bean>
</beans>

  proxyTargetClass属性,默认false,代理接口,此时Spring使用JDK动态代理

      如果是true,此时Spring使用CGLib动态代理。

客户端调用

package com.lhx.chapter4.aop.springaopintroductionadvice;

import com.lhx.chapter4.aop.Greeting;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client {
public static void main(String[] args) {
//获取spring content
ApplicationContext context =new ClassPathXmlApplicationContext("application-aop-intro.xml");
//从Content中根据id获取Bean对象,其实就是一个代理
Greeting greetingProxy = (Greeting) context.getBean("greetingProxy");
greetingProxy.sayHello("muzixu ");
Apology apology = (Apology) greetingProxy;
//将目标类强制向上转型为Apology接口类型【引入增强的特性,即“动态接口实现”功能】
apology.saySorry("Jack"); }
}

5、Spring AOP:切面

  之前说的AOP框架其实可以理解为一个拦截器框架,他拦截了一个类,其实就是拦截了所有方法。在使用动态代理时,也需要在代码中对所拦截的方法名加以判断,才能过滤出需要拦截的方法。

  Advisor【切面】封装了Advice【增强】与Pointcut【切面】。

增加两个以good开头的方法

package com.lhx.chapter4.aop.aoppointcut;

import com.lhx.chapter4.aop.Greeting;
import org.springframework.stereotype.Component; @Component
public class GreetingGood implements Greeting {
@Override
public void sayHello(String name) {
System.out.println("hello " + name);
} public void goodMorning(String name) {
System.out.println("goodMorning " + name);
} public void goodNight(String name) {
System.out.println("goodNight " + name);
} @Override
public void sayHelloThrows(String name) { }
}

基于正则表达式的切面类

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描指定包(将带有Compontent注解的类自动定义为Spring bean)-->
<context:component-scan base-package="com.lhx.chapter4.aop"></context:component-scan>
<!--配置一个切面-->
<bean id="pointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="greetingAroundAdvice"></property>
<property name="pattern" value="com.lhx.chapter4.aop.aoppointcut.GreetingGood.good.*"></property>
</bean>
<!--配置一个代理-->
<bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--接口实现类-->
<property name="target" ref="greetingGood"></property>
<!--拦截器名称(也是增强类名称,Spring Bean的id)-->
<property name="interceptorNames" value="pointcutAdvisor"></property>
<!--代理目标 false 接口 true 类 默认是false-->
<property name="proxyTargetClass" value="true"></property>
</bean>
</beans>

  interceptorNames不在是一个增强,而是一个切面。

  表达式中的".*",标示匹配所有字符。

Spring AOP提供的几个切面类

  RegexpMethodPointcutAdvisor

  DefaultPointcutAdvisor

  NameMatchMethodPointcutAdvisor

  AspectJExpressionPointcutAdvisor

6、Spring AOP:自动代理【扫面Bean名称】

增加spring xml配置

    <!--spring 自动代理-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!--只为后缀为Impl的Bean生成代理-->
<property name="beanNames" value="*Impl"></property>
<!--拦截器名称(也是增强类名称,Spring Bean的id)-->
<property name="interceptorNames" value="greetingAroundAdvice"></property>
<!--是否对代理生成策略进行优化-->
<property name="optimize" value="true"></property>
</bean>

  此处使用BeanNameAutoProxyCreator只为后缀为Impl的Bean生成代理类。

  这里提供了optimize配置项,默认为false, true含义:对生成策略进行优化,如果该类有接口,就代理接口(JDK动态代理),如果没有接口,就代理类(CGLib动态代理)。

  不像之前proxyTargetClass属性,强制代理类,而不考虑接口方式

既然有CGLib动态代理代理类,为什么还需要JDK动态代理?

  CGLib创建动态代理的速度较慢,但创建代理后运行速度却非常快。而JDK动态代理正好相反。如果在运行的时候不断的用CGLib创建代理, 系统性能会降低。

  所以建议一般在系统初始化的时候用CGLib去创建代理,并放入Spring的ApplicationContext中。

7、Spring AOP:自动代理【扫面切面配置】

  Spring的xml配置

    <!--配置一个切面-->
<bean id="pointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="greetingAroundAdvice"></property>
<property name="pattern" value="com.lhx.chapter4.aop.aoppointcut.GreetingGood.good.*"></property>
</bean>
<!--spring 自动代理 扫描切面-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<!--是否对代理生成策略进行优化-->
<property name="optimize" value="true"></property>
</bean>

  这里无需在配置代理,因为代理将由DefaultAdvisorAutoProxyCreator自动生成,这个类可以扫描所有的切面类,并未其自动生成代理。

2.3、spring+aspectj

  见下一节

  

005-搭建框架-实现AOP机制【二】AOP技术的更多相关文章

  1. Spring AOP编程(二)-AOP实现的三种方式

    AOP的实现有三种方式: l         aop底层将采用代理机制进行实现. l         接口 + 实现类 :spring采用 jdk 的动态代理Proxy. l         实现类: ...

  2. Castle框架中的IOC和AOP机制

    反转控制(IOC)和面向切面编程(AOP)技术作为当前比较流行的技术,其优势已受到广泛关注,但是这两项新技术在实际项目上的应用研究却很落后,而且在.NET平台下实现这两项技术没有形成可以广泛套用的框架 ...

  3. Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架

    类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...

  4. 006-搭建框架-实现AOP机制【三】AOP技术

    2.3.spring+aspectj Spring在集成了aspectj后,同时也保留了以上的切面与代理的配置方式. 将Spring与aspectj集成与直接使用aspectj不同,不需要定义Aspe ...

  5. Spring框架的核心功能之AOP技术

     技术分析之Spring框架的核心功能之AOP技术 AOP的概述        1. 什么是AOP的技术?        * 在软件业,AOP为Aspect Oriented Programming的 ...

  6. Spring 使用介绍(六)—— AOP(二)

    一.切入点语法 1)通配符 AOP支持的通配符: *:匹配任何数量字符 ..:匹配任何数量字符的重复,在类型模式中匹配任何数量子包,在方法参数模式中匹配任何数量参数 +:匹配指定类型的子类型,仅能作为 ...

  7. 深入理解Spring AOP之二代理对象生成

    深入理解Spring AOP之二代理对象生成 spring代理对象 上一篇博客中讲到了Spring的一些基本概念和初步讲了实现方法,当中提到了动态代理技术,包含JDK动态代理技术和Cglib动态代理 ...

  8. spring AOP 之二:@AspectJ注解的3种配置

    @AspectJ相关文章 <spring AOP 之二:@AspectJ注解的3种配置> <spring AOP 之三:使用@AspectJ定义切入点> <spring ...

  9. Spring 框架的核心功能之AOP技术

    1. AOP 的概述 AOP, Aspect Oriented Programming, 面向切面编程; 通过预编译方式和运行期动态代理实现程序功能的统一维护的技术; AOP 采取横向抽取机制,取代了 ...

  10. spring框架学习(六)AOP

    AOP(Aspect-OrientedProgramming)面向方面编程,与OOP完全不同,使用AOP编程系统被分为方面或关注点,而不是OOP中的对象. AOP的引入 在OOP面向对象的使用中,无可 ...

随机推荐

  1. CREATE SEQUENCE添加自增序列及NEXT VALUE FOR返回序列号

    From :https://msdn.microsoft.com/zh-cn/library/ff878091.aspx 语法: CREATE SEQUENCE [schema_name . ] se ...

  2. Atitit.软件开发的非功能性需求attilax 总结

    Atitit.软件开发的非功能性需求attilax 总结 1. 运行环境约束:用户对软件系统运行环境的要求. 1 2. 兼容性 2 3.   7.6 数据库 database (imp by ati) ...

  3. DMA (直接存储器访问)

    DMA (直接存储器访问) 编辑 DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载.否 ...

  4. Django中ORM介绍和字段参数

    Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...

  5. Vue 组件4 动态组件

    动态组件 通过使用保留的<component>元素,动态的绑定到它的is特性,我们让多个组件同时使用同一个挂载点,并动态切换: var vm = new Vue({ el: '#examp ...

  6. ntp集群时间同步

    1. NTP 简介 网络时间协议(英语:Network Time Protocol,简称NTP)是在数据网络潜伏时间可变的计算机系统之间通过分组交换进行时钟同步的一个网络协议.自1985年以来,NTP ...

  7. redis中毒

    黑客用我们服务器挖矿了 新的一天的开始 周五早上刚到公司,同事来问我系统为啥打不开了?我第一反应就是肯定 Nginx 服务器挂了呗,立马就去登录服务器看看,但此时发现已经完全远程登录不上这台部署了 N ...

  8. Java基础01 从HelloWorld到面向对象(转载)

    Java是完全面向对象的语言.Java通过虚拟机的运行机制,实现“跨平台”的理念. "Hello World!" public class HelloWorld{    publi ...

  9. ThinkPHP与EasyUI整合之二(datagrid):删除多条记录

    学习EasyUI已有一段时间了,现在开始逐步把平时学习的细节和难点记录下来. 1. datagrid选中多条记录的语句是: var rows = $('#dg').datagrid('getSelec ...

  10. Microsoft SQL Server JDBC 驱动程序支持矩阵

    本页包含 Microsoft SQL Server JDBC 驱动程序的支持矩阵和支持生命周期策略. Microsoft JDBC 驱动程序支持生命周期矩阵和策略 Microsoft 支持生命周期 ( ...