005-搭建框架-实现AOP机制【二】AOP技术
一、什么是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技术的更多相关文章
- Spring AOP编程(二)-AOP实现的三种方式
AOP的实现有三种方式: l aop底层将采用代理机制进行实现. l 接口 + 实现类 :spring采用 jdk 的动态代理Proxy. l 实现类: ...
- Castle框架中的IOC和AOP机制
反转控制(IOC)和面向切面编程(AOP)技术作为当前比较流行的技术,其优势已受到广泛关注,但是这两项新技术在实际项目上的应用研究却很落后,而且在.NET平台下实现这两项技术没有形成可以广泛套用的框架 ...
- Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架
类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...
- 006-搭建框架-实现AOP机制【三】AOP技术
2.3.spring+aspectj Spring在集成了aspectj后,同时也保留了以上的切面与代理的配置方式. 将Spring与aspectj集成与直接使用aspectj不同,不需要定义Aspe ...
- Spring框架的核心功能之AOP技术
技术分析之Spring框架的核心功能之AOP技术 AOP的概述 1. 什么是AOP的技术? * 在软件业,AOP为Aspect Oriented Programming的 ...
- Spring 使用介绍(六)—— AOP(二)
一.切入点语法 1)通配符 AOP支持的通配符: *:匹配任何数量字符 ..:匹配任何数量字符的重复,在类型模式中匹配任何数量子包,在方法参数模式中匹配任何数量参数 +:匹配指定类型的子类型,仅能作为 ...
- 深入理解Spring AOP之二代理对象生成
深入理解Spring AOP之二代理对象生成 spring代理对象 上一篇博客中讲到了Spring的一些基本概念和初步讲了实现方法,当中提到了动态代理技术,包含JDK动态代理技术和Cglib动态代理 ...
- spring AOP 之二:@AspectJ注解的3种配置
@AspectJ相关文章 <spring AOP 之二:@AspectJ注解的3种配置> <spring AOP 之三:使用@AspectJ定义切入点> <spring ...
- Spring 框架的核心功能之AOP技术
1. AOP 的概述 AOP, Aspect Oriented Programming, 面向切面编程; 通过预编译方式和运行期动态代理实现程序功能的统一维护的技术; AOP 采取横向抽取机制,取代了 ...
- spring框架学习(六)AOP
AOP(Aspect-OrientedProgramming)面向方面编程,与OOP完全不同,使用AOP编程系统被分为方面或关注点,而不是OOP中的对象. AOP的引入 在OOP面向对象的使用中,无可 ...
随机推荐
- filebeat 选项
Filebeat Options input_type: log|stdin 指定输入类型 paths 支持基本的正则,所有golang glob都支持,支持/var/log/*/*.log enco ...
- iOS9编程GOGOGO:XCode7新变化
做一个关于栈视图 UIStackView的Demo,先看看XCode7的变化 关于StoryBoard: 启动画面由xib变为Storyboard StoryBoard引用: 如今能够在一个Story ...
- error C2998: 'XXXXXXX' : cannot be a template definition 的可能原因。
从错误信息的字面意思可以看出来是 XXXXX 不能作为模板定义. 但是为什么不能,并没有说明,最后我翻阅各种资料,各种尝试后,发现往往可能是由于找不到模板函数的某个参数的定义而导致的. templat ...
- qsort的陷阱
问:求大神解释这个C程序,为什么在compare_strings中使用return strcmp(p, q);就无法正确排序 #include <string.h> #include &l ...
- LeetCode207. Course Schedule
Description There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses m ...
- jvisualvm远程调试
远程服务器端 (1)设置jstatd.all.policy 文件 grant codebase "file:${java.home}/../lib/tools.jar" { per ...
- wpf数据绑定更新通知
类似于这样子的;大致的意思是:一个代码变量,通过改变变量的值,绑定这个变量的这个圆颜色也在变化 就是一种心跳效果 在网上数据触发的感觉不多,废了不少时间,这里做个总结 1:通知 class Notif ...
- List ArrayList LinkedList 集合三
因为List是有顺序的说以API中定义了 方法来处理List Collections 接口:用于操作List集合有排序sort(list);查找int binarySearch(List,obj);c ...
- EasyNVR智能云终端硬件与EasyNVR解决方案软件综合对比
背景分析 互联网视频直播越来越成为当前视频直播的大势,对于传统的安防监控,一般都是局限于内网,无法成批量上云台.传统的海康和大华的平台虽然可以通过自身私有协议上云平台 集总管控,但是往往只是支持自身的 ...
- .NET架构师必备知识
.NET架构师,我归纳一下要学的知识: 成为优秀程序员,需要学好的知识: 1. 面向对象编程.UML画图.设计模式.代码重构 2. 常用ORM工具 3. MVC,WCF,XMl, JQuery ,S ...