本文主要对Spring AOP的相关概念和简单的静态代理、动态代理以及常见的几种AOP配置方式做总结学习。真诚希望大家给予批评和指导。
本文以自己写的一个简单Code为例,主要逻辑结构及说明信息依code中的注释内容为说明,所以可能出现 many codes little explianations.
接口:com.qian.subject.Subject –目标类RealSubject和代理类要实现的接口。
目标类: com.qian.realsubject.RealSubject
静态代理类: com.qian.staticproxy.SubjectStaticProxy
动态代理类: com.qian.dynamicproxy.SubjectDanamicProxy
package com.qian.subject;
/**
* 实际类RealSubject和代理类要实现的接口;
* @author Administrator
*/
public interface Subject {
public void addSub(String name, String password);
public String findSub(String id);
}
package com.qian.realsubject;
import com.qian.subject.*;
/**
* Subject的实现类,并重写方法
* @author Administrator
*
*/
public class RealSubject implements Subject {
public void addSub(String name, String password) {
System.out.println("RealSubject.addSub() "+ name+" "+ password);
}
public String findSub(String id) {
System.out.println("RealSubject.findSub() "+ id);
return "realSubject.findSub()";
}
}
package com.qian.staticproxy;
import com.qian.subject.Subject;
public class SubjectStaticProxy implements Subject {
//Remark: 拿到实际对象的引用;
private Subject realSubject;
//这里我们通过构造函数拿到;
public SubjectStaticProxy(Subject realSubject){
this.realSubject = realSubject;
}
public void addSub(String name, String password) {
System.out.println("staticProxy do something before realSubject.add()");
//调用实际对象的方法
realSubject.addSub(name, password);
}
public String findSub(String id) {
System.out.println("staticProxy do something before realSubject.findSub()");
return realSubject.findSub(id);
}
}
package com.qian.danamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class SubjectDanamicProxy implements InvocationHandler {
//实际要传入的realSubject;
private Object realSubject;
public Object getSubjectProxy(Object realSubject){
this.realSubject = realSubject;
//都是realSubject的;
Object proxy = Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
this);
//为了看看这个proxy和invoke(proxy)是否一样
System.out.println("--proxy=Prox.new...() is "+proxy.getClass().getName());
return proxy;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("--proxy in invoke parameters is "+proxy.getClass().getName());
checkInfo();
Object result = method.invoke(realSubject, args);
return result;
}
private void checkInfo(){
System.out.println("Doing some checking things before method invocation");
}
}
Aspectj类:com.qian.springaopaspectj.CheckInfoAspect
xml文件:applicationContextAspectj.xml
package com.qian.springaopaspectj;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 将 代理类中 都要做得检查操作(横切性关注点模块化)
* @author Administrator
*
*/
@Aspect //对横切性关注点的模块化;
public class CheckInfoAspect {
//定义advice应用到那些连接点上,也就是advice在应用程序上自行的点或者时机
//poincuName()就是给这个poincut起个名;
@Pointcut("execution(* add*(..)) || execution(* find*(..))")
private void poincutName(){}
//advice也就是关注点的具体实现;before在连接点JointPoint的前面使用
@Before("poincutName()")
public void checkInfo(){
System.out.println("Doing some checking things before method invocation");
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
<bean id="realSubject" class="com.qian.realsubject.RealSubject"/>
<bean id="checkInfoAspect" class="com.qian.springaopanno.CheckInfoAspect"/>
beans>
目标类:com.qian.realsubject.RealSubject
Advice类:com.qian.springaopxml.CheckInfoAspectXml
xml文件: applicationContextConfig.xml
package com.qian.springaopxml;
/**
* 模拟将遍布在系统流程中的检查信息(关注点)模块化成一个Aspect
* @author Administrator
*
*/
public class CheckInfoAspectXml {
public void checkInfo(){
System.out.println("Doing some checking things before method invocation");
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean id="realSubjectCGLIB" class="com.qian.realsubject.RealSubjectCGLIB"/>
<bean id="checkInfoAspectXml" class="com.qian.springaopxml.CheckInfoAspectXml"/>
<aop:config>
<aop:aspect id="checkInfoAspectXml" ref="checkInfoAspectXml">
<aop:pointcut expression="execution(* com.qian.realsubject.RealSubjectCGLIB.add*(..))||execution(* find*(..))" id="pointcut"/>
<aop:before method="checkInfo" pointcut-ref="pointcut"/>
aop:aspect>
aop:config>
beans>
类:com.qian.realsubject.RealSubjectCGLIB
Advice类:com.qian.springaopxml.CheckInfoAspectXml
xml文件: applicationContextConfigCGLIB.xml
package com.qian.realsubject;
/**
* 没有实现任何接口,我们用CGLIB来动态代理它
* @author Administrator
*
*/
public class RealSubjectCGLIB {
public void addSub(String name, String password) {
System.out.println("RealSubject.addSub() "+ name+" "+ password);
}
public String findSub(String id) {
System.out.println("RealSubject.findSub() "+ id);
return "realSubject.findSub()";
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean id="realSubjectCGLIB" class="com.qian.realsubject.RealSubjectCGLIB"/>
<bean id="checkInfoAspectXml" class="com.qian.springaopxml.CheckInfoAspectXml"/>
<aop:config>
<aop:aspect id="checkInfoAspectXml" ref="checkInfoAspectXml">
<aop:pointcut expression="execution(* com.qian.realsubject.RealSubjectCGLIB.add*(..))||execution(* find*(..))" id="pointcut"/>
<aop:before method="checkInfo" pointcut-ref="pointcut"/>
aop:aspect>
aop:config>
beans>
目标类 : com.qian.realsubject.RealSubjectBean
Advice类: com.qian.springaopproxy.RealSubjectBeanHelper –实现了接口 AfterReturningAdvice, MethodBeforeAdvice
xml文件:applicationContextProxy.xml
package com.qian.realsubject;
/**
* 为了说明 CGLIB 和spring 可以在 JDK动态代理和CGLIB切换
* 定义了一个没有实现任何借口的普通类;
* @author Administrator
*
*/
public class RealSubjectBean {
private String subName;
private String password;
public String getSubName() {
return subName;
}
public void setSubName(String subName) {
this.subName = subName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void addSubBean() {
System.out.println("RealSubjectBean.addSubBean() "+ subName+" "+ password);
}
public String findSubBean(String subName) {
System.out.println("RealSubjectBean.findSubBean() "+ subName);
return "realSubjectBean.findSubBean()";
}
}
package com.qian.springaopproxy;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
/**
* 使用spring 典型的动态代理来处理
* @author Administrator
*
*/
public class RealSubjectHelper implements AfterReturningAdvice, MethodBeforeAdvice {
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println(" RealSubjectHelper BeforMehtod: checking information");
}
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
System.out.println(" RealSubjectHelper AfterMehtod: checking information");
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean id="realSubjectBean" class="com.qian.realsubject.RealSubjectBean">
<property name="subName" value="zhangsan"/>
<property name="password" value="zhangsan123"/>
bean>
<bean id="realSubjectHelper" class="com.qian.springaopproxy.RealSubjectHelper"/>
<bean id="pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*find.*"/>
bean>
<bean id="pointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<constructor-arg name="pointcut" ref="pointcut"/>
<constructor-arg name="advice" ref="realSubjectHelper"/>
bean>
<bean id="realSubjectBeanProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="realSubjectBean"/>
<property name="interceptorNames">
<list>
<value>pointcutAdvisorvalue>
list>
property>
bean>
beans>
xml文件: applicationContextProxyV2.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean id="realSubjectBean" class="com.qian.realsubject.RealSubjectBean">
<property name="subName" value="zhangsan"/>
<property name="password" value="zhangsan123"/>
bean>
<bean id="realSubjectHelper" class="com.qian.springaopproxy.RealSubjectHelper"/>
<bean id="pointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="pattern" value=".*find.*"/>
<property name="advice" ref="realSubjectHelper"/>
bean>
<bean id="realSubjectBeanProxy" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
beans>
package com.qian.client;
import com.qian.realsubject.RealSubject;
import com.qian.realsubject.RealSubjectBean;
import com.qian.realsubject.RealSubjectCGLIB;
import com.qian.staticproxy.SubjectStaticProxy;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.qian.danamicproxy.SubjectDanamicProxy;
import com.qian.subject.Subject;
/**
* Client主测试类
* @author Administrator
*
*/
public class Client {
//最通俗易懂的办法 但是耦合度太高了
public static void subjectImpl(){
Subject subject = new RealSubject();
subject.addSub("qian", "520");
subject.findSub("511");
}
// 静态代理
public static void staticProxy(){
Subject subject = new SubjectStaticProxy(new RealSubject());
subject.addSub("name", "password");
subject.findSub("123");
}
// 动态代理
public static void dynamicProxy(){
Object proxy = new SubjectDanamicProxy().getSubjectProxy(new RealSubject());
Subject subject = (Subject)proxy;
subject.addSub("zhangsan", "pass123");
subject.findSub("134");
}
//使用 Aspectj.jar 和Aspectjweaver.jar 进行注释 推崇
public static void springaopAspectj(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextAspectj.xml");
Subject subject = (Subject) context.getBean("realSubject");
subject.addSub("spring", "aop");
subject.findSub("1231");
}
//使用spring的aop-config进行配置、推崇
public static void springaopConfig(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextConfig.xml");
Subject subject = (Subject) context.getBean("realSubject");
subject.addSub("spring", "aop");
subject.findSub("1231");
}
//对没有实现接口的类使用CGLIB 并使用spring的aop-config进行配置
public static void springaopConfigCGLIB(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextAopConfigCGLIB.xml");
RealSubjectCGLIB subject = (RealSubjectCGLIB) context.getBean("realSubjectCGLIB");
subject.addSub("spring", "aop");
subject.findSub("1231");
}
//spring AOP动态代理
public static void springaopProxy(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextProxy.xml");
RealSubjectBean subjectBean = (RealSubjectBean) context.getBean("realSubjectBeanProxy");
subjectBean.addSubBean();
subjectBean.findSubBean("springaop4");
}
//spirng AOP自动进行匹配的动态代理
public static void springaopProxyV2(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextProxyV2.xml");
RealSubjectBean subjectBean = (RealSubjectBean) context.getBean("realSubjectBean");
subjectBean.addSubBean();
subjectBean.findSubBean("springaop4");
}
public static void main(String[] args) {
//subjectImpl();
//staticProxy();
//dynamicProxy();
//springaopConfig();
//springaopConfigCGLIB();
//springaopProxy();
//springaopProxyV2();
}
}
结果都是预期的结果这里就不显示了。
本project使用的是Maven建的、所以pom.xml如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>springaopgroupId>
<artifactId>SpringAopartifactId>
<version>0.0.1-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>4.3.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>4.3.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>4.3.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>4.3.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjrtartifactId>
<version>1.8.5version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.8.5version>
dependency>
<dependency>
<groupId>cglibgroupId>
<artifactId>cglibartifactId>
<version>3.2.0version>
dependency>
dependencies>
project>
如果有想找完整版的src文件的朋友,可以留邮箱、
Thank you for your consideration. Thanks everyone. And I am grateful to those who give any comments or suggestions in the futrue.