AOP( Aspect Oriented Programming)是spring一项比较重要的应用,也称为面向切面编程。它对spring管理事务和安全管理等有着不可或缺的作用。那么,aop到底是如何实现面向切面的呢?它又是如何管理事务的呢?下面以一个简单示例说明面向切面编程。
1.Advisor接口IAudience:
package com.tan.app.interfaces;
public interface IAudience {
/**
* 入座,作为前置方法之一
*/
public void takeSite();
/**
* 关闭手机,作为前置方法之一
*/
public void turnOffCellphone();
/**
* 表扬,作为后置方法
*/
public void sayGood();
/**
* 诟病,作为抛出异常方法
*/
public void sayBad();
}
2.Audience,实现IAudience接口,作为环绕通知:
package com.tan.app.impl;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.stereotype.Component;
import com.tan.app.interfaces.IAudience;
/**
* 观众,作为切面
*/
@Component("audience")
public class Audience implements MethodInterceptor, IAudience
{
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
try {
this.takeSite();
this.turnOffCellphone();
Object result = methodInvocation.proceed();
this.sayGood();
return result;
}
catch (Exception e)
{
this.sayBad();
e.printStackTrace();
return null;
}
}
@Override
public void takeSite() {
System.out.println("观众入座……");
}
@Override
public void turnOffCellphone() {
System.out.println("大家关闭手机,等待表演开始……");
}
@Override
public void sayGood() {
System.out.println("表演很成功,Welldone!");
}
@Override
public void sayBad() {
System.out.println("表演出问题,糟糕!");
}
}
3.目标接口:IPerformlist
package com.tan.app.interfaces;
public interface IPerformlist
{
/**
* 表演者表演
*/
public void show();
}
4.目标类Performlist,实现IPerformlist
package com.tan.app.impl;
import org.springframework.stereotype.Component;
import com.tan.app.interfaces.IPerformlist;
/**
* 表演者,作为切面切入的目标对象
*
* @date: 2011-8-7上午10:14:04
*/
@Component("performlist")
public class Performlist implements IPerformlist
{
/**
* 表演者姓名
*/
private static String name;
public static void setName(String name) {
Performlist.name = name;
}
@Override
public void show()
{
System.out.println(name+"正在表演节目……");
}
}
5.代理接口:IPerformanceProxy:
package com.tan.app.impl;
import org.springframework.stereotype.Component;
import com.tan.app.interfaces.IPerformlist;
/**
* 表演者,作为切面切入的目标对象
*
* @date: 2011-8-7上午10:14:04
*/
@Component("performlist")
public class Performlist implements IPerformlist
{
/**
* 表演者姓名
*/
private static String name;
public static void setName(String name) {
Performlist.name = name;
}
@Override
public void show()
{
System.out.println(name+"正在表演节目……");
}
}
6.代理类PerformanceProxy,实现IPerformanceProxy:
package com.tan.app.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.tan.app.interfaces.IPerformanceProxy;
import com.tan.app.interfaces.IPerformlist;
/**
*
* 代理类
* @date: 2011-8-7上午10:25:20
*/
@Component("performanceProxy")
public class PerformanceProxy implements IPerformanceProxy
{
@Autowired
@Qualifier("performlist")
private IPerformlist performlist;
@Override
public void proxyWork()
{
Performlist.setName("卓别林");
this.performlist.show();
}
}
7.测试类:
package com.tan.app;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.tan.app.interfaces.IPerformanceProxy;
/**
* Aop Example
*
*/
public class AopApp
{
public static void main( String[] args )
{
ApplicationContext context=new ClassPathXmlApplicationContext("classpath:aopContextConfig.xml");
IPerformanceProxy performanceProxy=(IPerformanceProxy)context.getBean("myProxy");
performanceProxy.proxyWork();
}
}
8.aopContextConfig.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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.tan.app"/> <!-- <context:annotation-config/>--> <bean id="myProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>com.tan.app.interfaces.IPerformanceProxy</value> </property> <property name="interceptorNames"> <list> <value>audience</value> </list> </property> <property name="target"> <ref bean="performanceProxy"></ref> </property> </bean> </beans>
9.log4j.xml日志文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" > <log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' > <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> <param name="target" value="System.out"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}-%m%n" /> </layout> <!--过滤器设置输出的级别--> <filter class="org.apache.log4j.varia.LevelRangeFilter"> <param name="levelMin" value="debug" /> <param name="levelMax" value="warn" /> <param name="AcceptOnMatch" value="true" /> </filter> </appender> <appender name="FILE" class="org.apache.log4j.RollingFileAppender"> <!-- 设置日志输出文件名 --> <param name="File" value="./target/output.log" /> <!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 --> <param name="Append" value="true" /> <param name="MaxBackupIndex" value="10" /> <param name="encoding" value="UTF-8"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}-%m%n" /> </layout> </appender> <appender name="activexAppender" class="org.apache.log4j.DailyRollingFileAppender"> <param name="File" value="./target/activex.log" /> <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}-%m%n" /> </layout> </appender> <!-- 根logger的设置--> <root> <priority value ="debug"/> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </root> </log4j:configuration>
10.项目是用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.0</modelVersion> <groupId>com.tan.app</groupId> <artifactId>aopexample</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>aopexample</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.9</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>3.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>3.0.2.RELEASE</version> </dependency> </dependencies> <build> <finalName>${project.artifactId}-${version}</finalName> <sourceDirectory>src/main/java</sourceDirectory> <testSourceDirectory>src/test/java</testSourceDirectory> <resources> <resource> <directory>src/main/resources</directory> </resource> <resource> <directory>src/main/config</directory> </resource> </resources> <testResources> <testResource> <directory>src/test/resources</directory> </testResource> <testResource> <directory>src/test/config</directory> </testResource> </testResources> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.0</version> <extensions>false</extensions> <inherited>false</inherited> </plugin> </plugins> </pluginManagement> </build> </project>
11.结果输出:
2011-08-08 20:12:21-Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.tan.app.impl.PerformanceProxy@bc8e1e] 观众入座…… 大家关闭手机,等待表演开始…… 卓别林正在表演节目…… 表演很成功,Welldone!
12.后记:
AOP的实现原理其实是代理,有两种实现代理的模式:1.基于接口的代理,2.CGLIB。这里采用的是第一种基于接口的代理实现。在SSH开发中,AOP还有一个比较重要的应用
就是事务代理。就是通过spring的HibernateSessionFactory通过HibernateTransactionManager来管理项目中的数据库操作。