<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>绿色记忆 &#187; AspectJ</title>
	<atom:link href="https://blog.gmem.cc/tag/aspectj/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.gmem.cc</link>
	<description></description>
	<lastBuildDate>Mon, 13 Apr 2026 08:03:10 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.9.14</generator>
	<item>
		<title>Aspject加载时织入示例</title>
		<link>https://blog.gmem.cc/aspectj-load-time-weave-in</link>
		<comments>https://blog.gmem.cc/aspectj-load-time-weave-in#comments</comments>
		<pubDate>Sat, 13 Jul 2013 07:01:54 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[AspectJ]]></category>
		<category><![CDATA[Javassist]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=1678</guid>
		<description><![CDATA[<p>问题场景 最近的一个使用DDD风格建模的项目中，遇到这样的一个场景： 领域类的抽象类层次，作为Hibernate实体类使用，由于其包含了一些业务逻辑，需要Spring依赖注入的支持，故使用了@Configurable注解+AspectJ编译时织入的方式 具体领域类，一般没有业务逻辑，但是类数量较多，故使用Javassist进行自动的类生成 运行的时候出现问题了，使用Javassist生成的具体领域类，无法注入依赖，尽管其父类上有@Configurable注解。经过跟踪，发现子类也必须进行织入才能正常的进行依赖注入，那么，如何在生成字节码的时候，同时织入AOP逻辑呢？ AspectJ字节码织入工具类 其实AspectJ已经提供了加载时织入的API，下面这个工具类，即可用于织入任何指定的切面： [crayon-69dd6be89ee6a611623027/] 该工具类的一个实例，专门用于织入Spring aspects： [crayon-69dd6be89ee73093944816/] 在生成字节码时织入Spring-aspects 下面的例子中，首先生成了类的基本骨架，然后调用AspectJBytecodeWeaver进行织入。 [crayon-69dd6be89ee76318214619/]</p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/aspectj-load-time-weave-in">Aspject加载时织入示例</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h2"><span class="graybg">问题场景</span></div>
<p>最近的一个使用DDD风格建模的项目中，遇到这样的一个场景：</p>
<ol>
<li>领域类的抽象类层次，作为Hibernate实体类使用，由于其包含了一些业务逻辑，需要Spring依赖注入的支持，故使用了@Configurable注解+AspectJ编译时织入的方式</li>
<li>具体领域类，一般没有业务逻辑，但是类数量较多，故使用Javassist进行自动的类生成</li>
</ol>
<p>运行的时候出现问题了，使用Javassist生成的具体领域类，无法注入依赖，尽管其父类上有@Configurable注解。经过跟踪，发现子类也必须进行织入才能正常的进行依赖注入，那么，如何在生成字节码的时候，同时织入AOP逻辑呢？</p>
<div class="blog_h2"><span class="graybg">AspectJ字节码织入工具类</span></div>
其实AspectJ已经提供了加载时织入的API，下面这个工具类，即可用于织入任何指定的切面：<br />
<pre class="crayon-plain-tag">import java.lang.instrument.IllegalClassFormatException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.aspectj.weaver.loadtime.Aj;
import org.aspectj.weaver.loadtime.DefaultWeavingContext;
import org.aspectj.weaver.loadtime.definition.Definition;
import org.aspectj.weaver.tools.WeavingAdaptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Weave byte codes at load time.
 * 
 * @author Andrica Silviu
 * @author WangZhen
 */
public class AspectJBytecodeWeaver
{

    private static final Logger LOGGER = LoggerFactory.getLogger( AspectJBytecodeWeaver.class );

    private class DynamicAspectWeavingContext extends DefaultWeavingContext
    {

        public DynamicAspectWeavingContext( ClassLoader loader )
        {
            super( loader );
        }

        public List&lt;Definition&gt; getDefinitions( ClassLoader loader, WeavingAdaptor adaptor )
        {
            List&lt;Definition&gt; definitions = new ArrayList&lt;Definition&gt;();
            Definition d = new Definition();
            for ( String aspectName : aspectNames )
            {
                d.getAspectClassNames().add( aspectName );
            }
            d.appendWeaverOptions( "-Xjoinpoints:synchronization" );
            if ( LOGGER.isDebugEnabled() )
            {
                d.appendWeaverOptions( "-showWeaveInfo" );
            }
            definitions.add( d );
            return definitions;
        }

    }

    private final Map&lt;ClassLoader, Aj&gt; mapFromClassLoaderToAj;

    private final String[]             aspectNames;

    public AspectJBytecodeWeaver( String[] aspectName )
    {
        mapFromClassLoaderToAj = new ConcurrentHashMap&lt;ClassLoader, Aj&gt;();
        this.aspectNames = aspectName;
    }

    /**
     * Weaving delegation
     * 
     * @param loader
     *            the defining class loader
     * @param className
     *            the name of class beeing loaded
     * @param bytes
     *            the bytecode before weaving
     * @return the weaved bytecode
     */
    public byte[] weave( ClassLoader loader, String className, byte[] bytes ) throws IllegalClassFormatException
    {
        if ( className.replace( "/", "." ).equals( aspectNames ) )
        {
            return null;
        }
        Aj aj = getAj( loader );
        if ( LOGGER.isDebugEnabled() )
        {
            LOGGER.debug( "Weaving class : {} with aspect(s) :{}", className, Arrays.deepToString( aspectNames ) );
        }
        byte[] b = aj.preProcess( className, bytes, loader );
        return b;
    }

    private Aj getAj( ClassLoader loader )
    {
        if ( mapFromClassLoaderToAj.containsKey( loader ) )
        {
            return mapFromClassLoaderToAj.get( loader );
        }
        Aj aj = new Aj( new DynamicAspectWeavingContext( loader ) );
        mapFromClassLoaderToAj.put( loader, aj );
        return aj;
    }
}</pre><br />
该工具类的一个实例，专门用于织入Spring aspects：<br />
<pre class="crayon-plain-tag">public class SpringAspectJ
{
    private static final String               ASPECT_BEAN_CONFIG =
                                                                         "org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect";

    private static final String               ASPECT_SCHEDULING  =
                                                                         "org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect";

    private static final String               ASPECT_TRANSACTION =
                                                                         "org.springframework.transaction.aspectj.AnnotationTransactionAspect";

    private static final String               ASPECT_CACHE       =
                                                                         "org.springframework.cache.aspectj.AnnotationCacheAspect";

    public static final AspectJBytecodeWeaver WEAVER             = new AspectJBytecodeWeaver( new String[] {
                                                                 ASPECT_BEAN_CONFIG, ASPECT_SCHEDULING,
                                                                 ASPECT_TRANSACTION, ASPECT_CACHE } );
}</pre>
<div class="blog_h2"><span class="graybg">在生成字节码时织入Spring-aspects</span></div>
下面的例子中，首先生成了类的基本骨架，然后调用AspectJBytecodeWeaver进行织入。<br />
<pre class="crayon-plain-tag">ClassPool cp = ClassPool.getDefault();
ClassPath clsPath = new ClassClassPath( this.getClass() );
cp.insertClassPath( clsPath );
CtClass cc = cp.makeClass( getClassName() );
if ( StringUtils.isNotBlank( getSuperClassName() ) )
{
    cc.setSuperclass( cp.get( getSuperClassName() ) );
}
ClassFile cf = cc.getClassFile();
ConstPool constPool = cf.getConstPool();

if ( isWeaveSpringAspects() )
{
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    try
    {
        //织入Spring切面
        byte[] b = SpringAspectJ.WEAVER.weave( loader, getClassName(), cc.toBytecode() );
        cc.detach();
        cc = cp.makeClass( new ByteArrayInputStream( b ) );
    }
    catch ( IOException e )
    {
        throw new RuntimeException( e.getMessage(), e );
    }
}
Class&lt;?&gt; c = cc.toClass();
cc.detach();
return c;</pre>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/aspectj-load-time-weave-in">Aspject加载时织入示例</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/aspectj-load-time-weave-in/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring配置：集成Hibernate、JacksonJSON、AspectJ等框架</title>
		<link>https://blog.gmem.cc/spring-config-with-hibernate-jacksonjson-aspectj</link>
		<comments>https://blog.gmem.cc/spring-config-with-hibernate-jacksonjson-aspectj#comments</comments>
		<pubDate>Mon, 26 Nov 2012 08:39:24 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[AspectJ]]></category>
		<category><![CDATA[Cache]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[JacksonJSON]]></category>
		<category><![CDATA[Log4jdbc]]></category>
		<category><![CDATA[Scheduler]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[配置文件]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=1110</guid>
		<description><![CDATA[<p>本文提及的该套配置文件，覆盖了JavaEE项目开发的最常见需求，包括：依赖注入、事务控制、AOP、任务调度、缓存、MVC框架等方面的内容。 容易改变的配置项独立到属性文件中： [crayon-69dd6be89f421448215346/] Spring配置文件部分： [crayon-69dd6be89f425356258062/] Spring MVC配置文件部分： [crayon-69dd6be89f42b719229066/] ehcache配置部分： [crayon-69dd6be89f42f395871516/] Web.xml配置（使用了Spring的JavaConfig）： [crayon-69dd6be89f431050260311/] Java Config类： [crayon-69dd6be89f434504622204/] [crayon-69dd6be89f437068714226/] Maven依赖包列表： [crayon-69dd6be89f439573680269/] Maven插件配置（支持AspectJ）： [crayon-69dd6be89f43d046106388/]</p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/spring-config-with-hibernate-jacksonjson-aspectj">Spring配置：集成Hibernate、JacksonJSON、AspectJ等框架</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both">本文提及的该套配置文件，覆盖了JavaEE项目开发的最常见需求，包括：依赖注入、事务控制、AOP、任务调度、缓存、MVC框架等方面的内容。<br />
容易改变的配置项独立到属性文件中：<br />
<pre class="crayon-plain-tag">hibernateDialect=org.hibernate.dialect.MySQL5Dialect
#启用了log4jdbc支持
jdbcDriver=net.sf.log4jdbc.DriverSpy
jdbcDriverUrl=jdbc:log4jdbc:mysql://192.168.0.201:3306/initpemsdb1.1.1
jdbcUserName=root
jdbcPassword=root</pre><br />
Spring配置文件部分：<br />
<pre class="crayon-plain-tag">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;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:context="http://www.springframework.org/schema/context" 
    xmlns:util="http://www.springframework.org/schema/util" 
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:task="http://www.springframework.org/schema/task" 
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/task  http://www.springframework.org/schema/task/spring-task-3.0.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd
    "&gt;
    &lt;!-- 定义属性，在后面的配置中可以使用#{appCfg.xxx}引用 --&gt;
    &lt;util:properties id="appCfg" location="classpath:applicationConfig.properties" /&gt;
    &lt;!-- 包扫描配置 --&gt;
    &lt;context:component-scan base-package="cc.gmem.demo"&gt;
        &lt;!-- 去除Java Config类 --&gt;
        &lt;context:exclude-filter type="annotation" expression="org.springframework.context.annotation.Configuration" /&gt;
        &lt;!-- 去除Spring MVC类 --&gt;
        &lt;context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /&gt;
        &lt;!-- 匹配AspectJ Pattern的类被去除 --&gt;
        &lt;context:exclude-filter type="aspectj" expression="cc.gmem.demo.aop.web.*" /&gt;
    &lt;/context:component-scan&gt;
    &lt;!-- 启用注解支持 --&gt;
    &lt;context:annotation-config /&gt;
    &lt;!-- 支持@Configurable注解 --&gt;
    &lt;context:spring-configured /&gt;
    &lt;!--  启用注解方式的事务：基于AspectJ织入 --&gt;
    &lt;tx:annotation-driven transaction-manager="txManager" mode="aspectj" /&gt;
    &lt;!--  启用注解方式的缓存配置：基于AspectJ织入 --&gt;
    &lt;cache:annotation-driven cache-manager="cacheManager" mode="aspectj" /&gt;
    &lt;!--  启用注解方式的任务执行(例如@Async)：基于AspectJ织入 --&gt;
    &lt;task:annotation-driven executor="taskExecutor" mode="aspectj" /&gt;
    
    &lt;!--  任务调度器配置，pool-size为线程池大小，限制了同时最多被调度的任务 --&gt;
    &lt;task:scheduler pool-size="100" id="scheduler" /&gt;
    &lt;!-- 任务计划列表，支持固定频率、固定延迟、Cron表达式等 --&gt;
    &lt;task:scheduled-tasks scheduler="scheduler"&gt;
        &lt;task:scheduled fixed-rate="120000" method="run" ref="hibernateStatisticsMonitor" /&gt;
    &lt;/task:scheduled-tasks&gt;
    &lt;!-- 任务执行器，用于异步执行任务 --&gt;
    &lt;task:executor id="taskExecutor" keep-alive="3600" pool-size="10-100" queue-capacity="10000" rejection-policy="CALLER_RUNS" /&gt;
    &lt;!-- 引入其它Spring配置文件 --&gt;
    &lt;import resource="report-and-etl.xml" /&gt;  
    &lt;!-- Hibernate配置  --&gt;
    &lt;bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource"&gt;
        &lt;property name="alias" value="connectionPool" /&gt;
        &lt;property name="driver" value="#{appCfg.jdbcDriver}" /&gt;
        &lt;property name="driverUrl" value="#{appCfg.jdbcDriverUrl}" /&gt;
        &lt;property name="user" value="#{appCfg.jdbcUserName}" /&gt;
        &lt;property name="password" value="#{appCfg.jdbcPassword}" /&gt;
        &lt;property name="statistics" value="10s" /&gt;
        &lt;property name="minimumConnectionCount" value="10" /&gt;
        &lt;property name="maximumConnectionCount" value="100" /&gt;
        &lt;property name="simultaneousBuildThrottle" value="10" /&gt;
        &lt;property name="maximumActiveTime" value="3600000" /&gt;
    &lt;/bean&gt;
    &lt;bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" autowire="byName" /&gt;
    &lt;bean id="nativeJdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor" lazy-init="true" /&gt;
    &lt;bean id="sessionFactory" p:dataSource-ref="dataSource" class="cc.gmem.demo.hibernate.AnnotationSessionFactoryBean" depends-on="appCfg" &gt;
        &lt;property name="packagesToScan"&gt;
            &lt;list&gt;
                &lt;value&gt;cc.gmem.demo.**.domain&lt;/value&gt;
            &lt;/list&gt;
        &lt;/property&gt;
        &lt;property name="hibernateProperties"&gt;
            &lt;value&gt;
                hibernate.dialect=#{appCfg.hibernateDialect}
                hibernate.jdbc.batch_size=30
                hibernate.show_sql=false
                hibernate.format_sql=true
                hibernate.generate_statistics=true
                hibernate.transaction.factory_class=org.hibernate.transaction.JDBCTransactionFactory
                hibernate.current_session_context_class=org.springframework.orm.hibernate3.SpringSessionContext
                hibernate.query.factory_class=org.hibernate.hql.ast.ASTQueryTranslatorFactory
                hibernate.hbm2ddl.auto=update
                #启用二级缓存
                hibernate.cache.use_second_level_cache=true
                hibernate.cache.use_query_cache=true
                hibernate.cache.region.factory_class=org.hibernate.cache.SingletonEhCacheRegionFactory
            &lt;/value&gt;
        &lt;/property&gt;
    &lt;/bean&gt;
    &lt;!-- Spring缓存配置 --&gt;
    &lt;bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"&gt;
        &lt;property name="cacheManager" ref="ehcache" /&gt;
    &lt;/bean&gt;
    &lt;bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&gt;
        &lt;property name="configLocation"&gt;
            &lt;value&gt;classpath:ehcache.xml&lt;/value&gt;
        &lt;/property&gt;
        &lt;property name="shared" value="true" /&gt;
    &lt;/bean&gt;
    &lt;bean id="hibernateStatisticsMonitor" class="cc.gmem.demo.hibernate.HibernateStatisticsMonitor" /&gt;
    &lt;bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory" /&gt;
    &lt;!-- Velocity引擎配置 --&gt;
    &lt;bean id="velocityEngine" class="org.apache.velocity.app.VelocityEngine"&gt;
        &lt;constructor-arg type="java.util.Properties"&gt;
            &lt;value&gt;
                &lt;![CDATA[
                #{T(org.apache.velocity.runtime.RuntimeConstants).RUNTIME_LOG_LOGSYSTEM_CLASS}=org.apache.velocity.runtime.log.Log4JLogChute
                runtime.log.logsystem.log4j.logger=velocityLogger
                #{T(org.apache.velocity.runtime.RuntimeConstants).INPUT_ENCODING}=UTF-8
                #{T(org.apache.velocity.runtime.RuntimeConstants).OUTPUT_ENCODING}=UTF-8
                #{T(org.apache.velocity.runtime.RuntimeConstants).VM_PERM_ALLOW_INLINE}=true
                #{T(org.apache.velocity.runtime.RuntimeConstants).RESOURCE_LOADER}=class
                #{T(org.apache.velocity.runtime.RuntimeConstants).PARSER_POOL_SIZE}=100
                class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
                ]]&gt;
            &lt;/value&gt;
        &lt;/constructor-arg&gt;
    &lt;/bean&gt;
    &lt;!--国际化支持--&gt;
    &lt;bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"&gt;
         &lt;property name="basenames"&gt;
             &lt;list&gt;
                 &lt;value&gt;classpath:message.gmemdemo&lt;/value&gt;
             &lt;/list&gt;
         &lt;/property&gt;
         &lt;property name="defaultEncoding" value="UTF-8" /&gt;
         &lt;property name="cacheSeconds" value="5" /&gt;
    &lt;/bean&gt;
    &lt;!--Jackson JSON --&gt;
    &lt;bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" autowire="byType" /&gt;
    &lt;!-- Spring类型转换服务，特别是用于时间日期格式转换 --&gt;
    &lt;bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"&gt;
        &lt;property name="converters"&gt;
            &lt;set&gt;
                &lt;bean class="net.greenmemory.spring.converter.DateTimeConvertor"&gt;
                    &lt;constructor-arg&gt;
                        &lt;array&gt;
                            &lt;value&gt;yyyy-MM-dd&lt;/value&gt;
                            &lt;value&gt;yyyy-MM-dd HH:mm:ss&lt;/value&gt;
                            &lt;value&gt;yyyy-MM-dd HH:mm:ss.SSS&lt;/value&gt;
                       &lt;/array&gt;
                    &lt;/constructor-arg&gt;
                &lt;/bean&gt;
            &lt;/set&gt;
       &lt;/property&gt;
       &lt;property name="formatters"&gt;
           &lt;set&gt;
               &lt;bean class="org.springframework.format.datetime.DateFormatter"&gt;
                   &lt;constructor-arg&gt;
                       &lt;value&gt;yyyy-MM-dd&lt;/value&gt;
                   &lt;/constructor-arg&gt;
               &lt;/bean&gt;
           &lt;/set&gt;
       &lt;/property&gt;
       &lt;property name="formatterRegistrars"&gt;
           &lt;set&gt;
           &lt;/set&gt;
       &lt;/property&gt;
    &lt;/bean&gt;
&lt;/beans&gt;</pre><br />
Spring MVC配置文件部分：<br />
<pre class="crayon-plain-tag">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans 
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    "&gt;
    &lt;context:component-scan base-package="cc.gmem.demo.**.ctrl"&gt;
        &lt;context:exclude-filter type="annotation" expression="org.springframework.context.annotation.Configuration" /&gt;
    &lt;/context:component-scan&gt;
    &lt;context:component-scan base-package="cc.gmem.demo.aop.web" /&gt;

    &lt;context:annotation-config /&gt;

    &lt;mvc:annotation-driven&gt;
        &lt;mvc:message-converters&gt;
            &lt;bean class="org.springframework.http.converter.json.jacksonjson.MappingJackson2HttpMessageConverter"&gt;
                &lt;property name="objectMapper" ref="objectMapper" /&gt;
            &lt;/bean&gt;
        &lt;/mvc:message-converters&gt;
    &lt;/mvc:annotation-driven&gt;

    &lt;mvc:interceptors&gt;
        &lt;bean id="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"&gt;
            &lt;property name="sessionFactory" ref="sessionFactory" /&gt;
        &lt;/bean&gt;
            &lt;mvc:interceptor&gt;     
            &lt;mvc:mapping path="/home/*" /&gt; 
            &lt;!-- 自定义MVC拦截器 --&gt;
            &lt;bean class="cc.gmem.demo.spring.LogonInterceptor" /&gt; 
        &lt;/mvc:interceptor&gt;  
        
    &lt;/mvc:interceptors&gt;

    &lt;bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"&gt;
        &lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /&gt;
        &lt;property name="prefix" value="/WEB-INF/jsp/" /&gt;
        &lt;property name="suffix" value=".jsp" /&gt;
        &lt;property name="order" value="0" /&gt;
    &lt;/bean&gt;

    &lt;mvc:resources mapping="/css/**" location="/css/" /&gt;
    &lt;mvc:resources mapping="/icons/**" location="/icons/" /&gt;
    &lt;mvc:resources mapping="/images/**" location="/images/" /&gt;
    &lt;mvc:resources mapping="/themes/**" location="/themes/" /&gt;
    &lt;mvc:resources mapping="/js/**" location="/js/" /&gt;
&lt;/beans&gt;</pre><br />
ehcache配置部分：<br />
<pre class="crayon-plain-tag">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;ehcache&gt;
    &lt;diskStore path="D:/Temp/ehcache" /&gt;
    &lt;defaultCache eternal="false" /&gt;
    &lt;cache name="entityCache" eternal="false" maxElementsInMemory="1000" timeToIdleSeconds="120" timeToLiveSeconds="3600"
        overflowToDisk="true" memoryStoreEvictionPolicy="LFU" /&gt;
&lt;/ehcache&gt;</pre><br />
Web.xml配置（使用了Spring的JavaConfig）：<br />
<pre class="crayon-plain-tag">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"&gt;
    &lt;context-param&gt;
        &lt;param-name&gt;contextClass&lt;/param-name&gt;
        &lt;param-value&gt;org.springframework.web.context.support.AnnotationConfigWebApplicationContext&lt;/param-value&gt;
    &lt;/context-param&gt;
    &lt;context-param&gt;
        &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
        &lt;param-value&gt;cc.gmem.demo.spring.SpringBeanDefinitionRegistrar&lt;/param-value&gt;
    &lt;/context-param&gt;
    &lt;listener&gt;
        &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
    &lt;/listener&gt;
    &lt;servlet&gt;
        &lt;servlet-name&gt;springmvc&lt;/servlet-name&gt;
        &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;contextClass&lt;/param-name&gt;
            &lt;param-value&gt;org.springframework.web.context.support.AnnotationConfigWebApplicationContext&lt;/param-value&gt;
        &lt;/init-param&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
            &lt;param-value&gt;cc.gmem.demo.spring.SpringMVCBeanDefinitionRegistrar&lt;/param-value&gt;
        &lt;/init-param&gt;
    &lt;/servlet&gt;
    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;springmvc&lt;/servlet-name&gt;
        &lt;url-pattern&gt;/&lt;/url-pattern&gt;
    &lt;/servlet-mapping&gt;

    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;adminServlet&lt;/servlet-name&gt;
        &lt;url-pattern&gt;/proxool&lt;/url-pattern&gt;
    &lt;/servlet-mapping&gt;

    &lt;session-config&gt;
        &lt;session-timeout&gt;60&lt;/session-timeout&gt;
    &lt;/session-config&gt;

    &lt;error-page&gt;
        &lt;error-code&gt;404&lt;/error-code&gt;
        &lt;location&gt;/WEB-INF/jsp/error-404.jsp&lt;/location&gt;
    &lt;/error-page&gt;
    &lt;error-page&gt;
        &lt;error-code&gt;401&lt;/error-code&gt;
        &lt;location&gt;/WEB-INF/jsp/error-401.jsp&lt;/location&gt;
    &lt;/error-page&gt;
    &lt;error-page&gt;
        &lt;error-code&gt;500&lt;/error-code&gt;
        &lt;location&gt;/WEB-INF/jsp/error-500.jsp&lt;/location&gt;
    &lt;/error-page&gt;
     &lt;welcome-file-list&gt;
        &lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;
    &lt;/welcome-file-list&gt;
&lt;/web-app&gt;</pre><br />
Java Config类：<br />
<pre class="crayon-plain-tag">@Configuration
/* XML-based bean definitions */
@ImportResource ( "classpath:applicationContext.xml" )
public class SpringBeanDefinitionRegistrar
{

    /* Auto injected spring context */
    @SuppressWarnings ( "unused" )
    @Inject
    private ApplicationContext applicationContext;

    /* Programmatic bean definition */
    @Bean ( name = "helper" )
    public Helper helper()
    {
        Helper helper = new Helper();
        return helper;
    }

}</pre><br />
<pre class="crayon-plain-tag">@Configuration
@ImportResource ( "classpath:spring-mvc.xml" )
public class SpringMVCBeanDefinitionRegistrar
{

}</pre><br />
Maven依赖包列表：<br />
<pre class="crayon-plain-tag">&lt;properties&gt;
    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
    &lt;spring.version&gt;3.1.2.RELEASE&lt;/spring.version&gt;
    &lt;hibernate.version&gt;3.6.10.Mod&lt;/hibernate.version&gt;
    &lt;aspectj.version&gt;1.6.11&lt;/aspectj.version&gt;
    &lt;jackson.version&gt;2.0.4&lt;/jackson.version&gt;
&lt;/properties&gt;
&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework&lt;/groupId&gt;
        &lt;artifactId&gt;spring-core&lt;/artifactId&gt;
        &lt;version&gt;${spring.version}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework&lt;/groupId&gt;
        &lt;artifactId&gt;spring-jdbc&lt;/artifactId&gt;
        &lt;version&gt;${spring.version}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework&lt;/groupId&gt;
        &lt;artifactId&gt;spring-beans&lt;/artifactId&gt;
        &lt;version&gt;${spring.version}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework&lt;/groupId&gt;
        &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;
        &lt;version&gt;${spring.version}&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework&lt;/groupId&gt;
        &lt;artifactId&gt;spring-orm&lt;/artifactId&gt;
        &lt;version&gt;${spring.version}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework&lt;/groupId&gt;
        &lt;artifactId&gt;spring-test&lt;/artifactId&gt;
        &lt;version&gt;${spring.version}&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;org.hibernate&lt;/groupId&gt;
        &lt;artifactId&gt;hibernate-core&lt;/artifactId&gt;
        &lt;version&gt;${hibernate.version}&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;org.aspectj&lt;/groupId&gt;
        &lt;artifactId&gt;aspectjweaver&lt;/artifactId&gt;
        &lt;version&gt;${aspectj.version}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.aspectj&lt;/groupId&gt;
        &lt;artifactId&gt;aspectjrt&lt;/artifactId&gt;
        &lt;version&gt;${aspectj.version}&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
        &lt;artifactId&gt;jackson-core&lt;/artifactId&gt;
        &lt;version&gt;${jackson.version}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
        &lt;artifactId&gt;jackson-databind&lt;/artifactId&gt;
        &lt;version&gt;${jackson.version}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
        &lt;artifactId&gt;jackson-annotations&lt;/artifactId&gt;
        &lt;version&gt;${jackson.version}&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
        &lt;artifactId&gt;servlet-api&lt;/artifactId&gt;
        &lt;version&gt;2.4&lt;/version&gt;
        &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;javax.servlet.jsp&lt;/groupId&gt;
        &lt;artifactId&gt;jsp-api&lt;/artifactId&gt;
        &lt;version&gt;2.0&lt;/version&gt;
        &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
        &lt;artifactId&gt;jstl&lt;/artifactId&gt;
        &lt;version&gt;1.2&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;taglibs&lt;/groupId&gt;
        &lt;artifactId&gt;standard&lt;/artifactId&gt;
        &lt;version&gt;1.1.2&lt;/version&gt;
        &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;javax.el&lt;/groupId&gt;
        &lt;artifactId&gt;el-api&lt;/artifactId&gt;
        &lt;version&gt;2.2&lt;/version&gt;
        &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;proxool&lt;/groupId&gt;
        &lt;artifactId&gt;proxool&lt;/artifactId&gt;
        &lt;version&gt;0.9.1&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;org.javassist&lt;/groupId&gt;
        &lt;artifactId&gt;javassist&lt;/artifactId&gt;
        &lt;version&gt;3.15.0-GA&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;net.sf.log4jdbc&lt;/groupId&gt;
        &lt;artifactId&gt;log4jdbc3&lt;/artifactId&gt;
        &lt;version&gt;1.2-ext-3&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.sqlinform&lt;/groupId&gt;
        &lt;artifactId&gt;sqlinform&lt;/artifactId&gt;
        &lt;version&gt;0.0.1&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;javax.annotation&lt;/groupId&gt;
        &lt;artifactId&gt;jsr250-api&lt;/artifactId&gt;
        &lt;version&gt;1.0&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;javax.inject&lt;/groupId&gt;
        &lt;artifactId&gt;javax.inject&lt;/artifactId&gt;
        &lt;version&gt;1&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;joda-time&lt;/groupId&gt;
        &lt;artifactId&gt;joda-time&lt;/artifactId&gt;
        &lt;version&gt;2.1&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;cglib&lt;/groupId&gt;
        &lt;artifactId&gt;cglib&lt;/artifactId&gt;
        &lt;version&gt;2.2.2&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;org.apache.poi&lt;/groupId&gt;
        &lt;artifactId&gt;poi&lt;/artifactId&gt;
        &lt;version&gt;3.9&lt;/version&gt;
    &lt;/dependency&gt;
    
    &lt;dependency&gt;
        &lt;groupId&gt;opensymphony&lt;/groupId&gt;
        &lt;artifactId&gt;quartz-all&lt;/artifactId&gt;
        &lt;version&gt;1.6.3&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;</pre><br />
Maven插件配置（支持AspectJ）：<br />
<pre class="crayon-plain-tag">&lt;plugin&gt;
    &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
    &lt;artifactId&gt;aspectj-maven-plugin&lt;/artifactId&gt;
    &lt;version&gt;1.4&lt;/version&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;id&gt;compile&lt;/id&gt;
            &lt;configuration&gt;
                &lt;XnoInline&gt;true&lt;/XnoInline&gt;
                &lt;forceAjcCompile&gt;true&lt;/forceAjcCompile&gt;
                &lt;showWeaveInfo&gt;true&lt;/showWeaveInfo&gt;
                &lt;source&gt;1.5&lt;/source&gt;
                &lt;target&gt;1.5&lt;/target&gt;
                &lt;encoding&gt;UTF-8&lt;/encoding&gt;
                &lt;verbose&gt;true&lt;/verbose&gt;
                &lt;outxml&gt;true&lt;/outxml&gt;
                &lt;aspectLibraries&gt;
                    &lt;aspectLibrary&gt;
                        &lt;groupId&gt;org.springframework&lt;/groupId&gt;
                        &lt;artifactId&gt;spring-aspects&lt;/artifactId&gt;
                    &lt;/aspectLibrary&gt;
                &lt;/aspectLibraries&gt;
            &lt;/configuration&gt;
            &lt;goals&gt;
                &lt;goal&gt;compile&lt;/goal&gt;
            &lt;/goals&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
&lt;/plugin&gt;</pre>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/spring-config-with-hibernate-jacksonjson-aspectj">Spring配置：集成Hibernate、JacksonJSON、AspectJ等框架</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/spring-config-with-hibernate-jacksonjson-aspectj/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Eclipse下进行基于AspectJ的AOP编程</title>
		<link>https://blog.gmem.cc/aspectj-aop-programming-with-eclipse</link>
		<comments>https://blog.gmem.cc/aspectj-aop-programming-with-eclipse#comments</comments>
		<pubDate>Wed, 06 Jun 2012 05:48:41 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[AspectJ]]></category>
		<category><![CDATA[Eclipse]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=1660</guid>
		<description><![CDATA[<p>简述 本文介绍在Eclipse下，结合Maven进行基于AspectJ的AOP编程（编译期织入）的基础知识，并给出简单的示例。 本文中使用的Eclipse版本为：3.7.1，AJDT版本为：1.6 环境准备 安装AspectJ Development Tools（AJDT）插件 可以到Eclipse Marketplace搜索“AJDT”，注意版本要和你的Eclipse版本匹配。或者从Update Site：http://download.eclipse.org/tools/ajdt/37/update/等位置安装，37表示Eclipse的版本为3.7。如果安装不成功，可以到AJDT网站下载离线安装包：http://www.eclipse.org/aspectj/downloads.php 可以使用aspectj-maven-plugin插件，让Maven支持AspectJ编译器织入。为了使用该插件，必须安装： i)：AJDT Configurator：Update Site为 http://dist.springsource.org/release/AJDT/configurator/ ii)：m2e connector for build-helper-maven-plugin：到Eclipse Marketplace搜索并安装 创建AspectJ工程 安装完AJDT后重启Eclipse，即可通过File - <a class="read-more" href="https://blog.gmem.cc/aspectj-aop-programming-with-eclipse">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/aspectj-aop-programming-with-eclipse">Eclipse下进行基于AspectJ的AOP编程</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h2"><span class="graybg">简述</span></div>
<p>本文介绍在Eclipse下，结合Maven进行基于AspectJ的AOP编程（编译期织入）的基础知识，并给出简单的示例。 本文中使用的Eclipse版本为：3.7.1，AJDT版本为：1.6</p>
<div class="blog_h2"><span class="graybg">环境准备</span></div>
<ol>
<li>安装AspectJ Development Tools（AJDT）插件 可以到Eclipse Marketplace搜索“AJDT”，注意版本要和你的Eclipse版本匹配。或者从Update Site：http://download.eclipse.org/tools/ajdt/37/update/等位置安装，37表示Eclipse的版本为3.7。如果安装不成功，可以到AJDT网站下载离线安装包：<a href="http://www.eclipse.org/aspectj/downloads.php">http://www.eclipse.org/aspectj/downloads.php</a></li>
<li>可以使用aspectj-maven-plugin插件，让Maven支持AspectJ编译器织入。为了使用该插件，必须安装：<br />
	i)：AJDT Configurator：Update Site为 http://dist.springsource.org/release/AJDT/configurator/<br />
	ii)：m2e connector for build-helper-maven-plugin：到Eclipse Marketplace搜索并安装</li>
</ol>
<div class="blog_h2"><span class="graybg">创建AspectJ工程</span></div>
安装完AJDT后重启Eclipse，即可通过File - New - AspectJ Project新建AspectJ工程了。不过最好通过Maven来创建，以提高工程的可移植性。 只需要在POM中配置aspectj-maven-plugin，然后右键 - Maven - Update Project，Eclipse工程结构即可自动生成，典型的aspectj-maven-plugin配置内容如下：<br />
<pre class="crayon-plain-tag">&lt;build&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
            &lt;artifactId&gt;aspectj-maven-plugin&lt;/artifactId&gt;
            &lt;version&gt;1.4&lt;/version&gt;
            &lt;executions&gt;
                &lt;execution&gt;
                    &lt;id&gt;compile&lt;/id&gt;
                    &lt;configuration&gt;
                        &lt;XnoInline&gt;true&lt;/XnoInline&gt;
                        &lt;forceAjcCompile&gt;true&lt;/forceAjcCompile&gt;
                        &lt;showWeaveInfo&gt;true&lt;/showWeaveInfo&gt;
                        &lt;source&gt;1.5&lt;/source&gt;
                        &lt;target&gt;1.5&lt;/target&gt;
                        &lt;encoding&gt;UTF-8&lt;/encoding&gt;
                        &lt;verbose&gt;true&lt;/verbose&gt;
                        &lt;outxml&gt;true&lt;/outxml&gt;
                        &lt;aspectLibraries&gt;
                            &lt;aspectLibrary&gt;
                                &lt;!-- 在这里声明需要用到的切面库，这些库里面包含AspectJ切面的定义 --&gt;
                                &lt;!-- 切面库同时需要作为dependency配置 --&gt;
                                &lt;groupId&gt;org.springframework&lt;/groupId&gt;
                                &lt;artifactId&gt;spring-aspects&lt;/artifactId&gt;
                            &lt;/aspectLibrary&gt;
                        &lt;/aspectLibraries&gt;
                    &lt;/configuration&gt;
                    &lt;goals&gt;
                        &lt;goal&gt;compile&lt;/goal&gt;
                        &lt;goal&gt;test-compile&lt;/goal&gt;&lt;!-- 如果/src/test/java下没有任何类使用了AOP，则需要去掉这一行，否则Maven执行报错（1.4版本） --&gt;
                    &lt;/goals&gt;
                &lt;/execution&gt;
            &lt;/executions&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/build&gt;</pre>
<div class="blog_h2"><span class="graybg">应用举例</span></div>
使用Spring-aspects库提供的支持，我们可以在任何类————甚至是AspectJ切面本身————上添加注解：@Configurable，每当创建该类的实例时，Spring自动对其进行依赖注入，下面是一个例子：<br />
<pre class="crayon-plain-tag">package cc.gmem.demo.aop.web;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Configurable;

import cc.gmem.demo.ext.ExtAjaxResult;
import cc.gmem.demo.ext.ExtAjaxResultCallback;
import cc.gmem.demo.ext.ExtAjaxResultTemplate;

@Configurable
public aspect AjaxResultAspect issingleton() {

    private static final Logger   LOGGER = LoggerFactory.getLogger( AjaxResultAspect.class );

    @Inject
    private ExtAjaxResultTemplate ajaxTemplate;

    @PostConstruct
    public void init()
    {
        LOGGER.debug( "AjaxResultAspect initialized." );
    }

    public pointcut autoExtAjaxResultMarked() :@annotation(AutoExtAjaxResult);

    @SuppressAjWarnings
    Object around():autoExtAjaxResultMarked(){
        return ajaxTemplate.callback( new ExtAjaxResultCallback() {

            public Void callback( ExtAjaxResult result ) throws Throwable
            {
                Object retVal = proceed();
                result.setObject( retVal );
                return VOID;
            }
        } );
    }
}</pre><br />
上面例子编译后（Eclipse或者Maven），产生类：AjaxResultAspect.class，如果用反编译工具打开，即可看到类似下面的、由AspectJ在编译器织入到字节码的内容：<br />
<pre class="crayon-plain-tag">//整个static块均为织入的内容
static
{
  ajc$preClinit();
  try { LOGGER = LoggerFactory.getLogger(AjaxResultAspect.class); ajc$postClinit(); } catch (Throwable localThrowable) { ajc$initFailureCause = localThrowable; }
}
//构造器的代码为织入的内容，包含了进行Spring依赖注入的逻辑
public AjaxResultAspect()
{
  JoinPoint localJoinPoint2 = Factory.makeJP(ajc$tjp_1, this, this); JoinPoint localJoinPoint1 = Factory.makeJP(ajc$tjp_0, this, this); if ((this != null) &amp;&amp; (getClass().isAnnotationPresent(Configurable.class)) &amp;&amp; (AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)getClass().getAnnotation(Configurable.class)))) AnnotationBeanConfigurerAspect.aspectOf().ajc$before$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$1$e854fa65(this); if (((this == null) || (!getClass().isAnnotationPresent(Configurable.class)) || (!AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)getClass().getAnnotation(Configurable.class)))) &amp;&amp; (this != null) &amp;&amp; (getClass().isAnnotationPresent(Configurable.class)) &amp;&amp; (AbstractDependencyInjectionAspect.ajc$if$6f1(localJoinPoint1))) AnnotationBeanConfigurerAspect.aspectOf().ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(this); if ((!AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)getClass().getAnnotation(Configurable.class))) &amp;&amp; (AbstractDependencyInjectionAspect.ajc$if$6f1(localJoinPoint2))) AnnotationBeanConfigurerAspect.aspectOf().ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(this);
}</pre>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/aspectj-aop-programming-with-eclipse">Eclipse下进行基于AspectJ的AOP编程</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/aspectj-aop-programming-with-eclipse/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AspectJ编程学习笔记</title>
		<link>https://blog.gmem.cc/aspectj-study-note</link>
		<comments>https://blog.gmem.cc/aspectj-study-note#comments</comments>
		<pubDate>Sun, 10 Apr 2011 02:20:04 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[AOP]]></category>
		<category><![CDATA[AspectJ]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[学习笔记]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=1697</guid>
		<description><![CDATA[<p>AOP基本概念 名词  含义 切面（方面，Aspect） 一个关注点的模块化，这个关注点实现可能横切（crosscutting）多个对象切面的例子包括：事务控制、日志记录、权限控制等在AspectJ中，切面表现为Java类，其源码具有AspectJ的特殊语法增强，使用ajc编译器编译 连接点（Joinpoint） 程序执行过程中明确的点，例如方法的调用开始、结束，或者特定的异常被抛出，横切（crosscutting）在连接点发生 通知（Advice） 在特定的连接点，AOP框架执行的操作 切入点（Pointcut） 切入点是这样的一种程序构造：包含一个连接点的集合、以及收集的连接点的上下文信息（例如方法参数、被执行方法和对象）。通知在这些切入点被触发。AOP框架允许开发者以多种方式定义切入点 引入（Introduction） 添加方法、字段、接口、注解等到被通知的类 目标对象（Target Object） 包含连接点的对象，也被称作被通知或被代理对象 AOP代理（AOP Proxy） AOP框架创建的对象，以目标对象为基础，织入了通知逻辑代理主要包括动态代理、字节码增强两种类型 AspectJ基础知识 AspectJ编译器能识别任何普通的Java代码，可以使用ajc编译.java文件 织入方式： <a class="read-more" href="https://blog.gmem.cc/aspectj-study-note">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/aspectj-study-note">AspectJ编程学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h2"><span class="graybg">AOP基本概念</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">名词</td>
<td style="text-align: center;"> 含义</td>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 200px;">切面（方面，Aspect）</td>
<td>一个关注点的模块化，这个关注点实现可能横切（crosscutting）多个对象切面的例子包括：事务控制、日志记录、权限控制等在AspectJ中，切面表现为Java类，其源码具有AspectJ的特殊语法增强，使用ajc编译器编译</td>
</tr>
<tr>
<td>连接点（Joinpoint）</td>
<td>程序执行过程中明确的点，例如方法的调用开始、结束，或者特定的异常被抛出，横切（crosscutting）在连接点发生</td>
</tr>
<tr>
<td>通知（Advice）</td>
<td>在特定的连接点，AOP框架执行的操作</td>
</tr>
<tr>
<td>切入点（Pointcut）</td>
<td>切入点是这样的一种程序构造：包含<strong>一个连接点的集合、以及收集的连接点的上下文信息</strong>（例如方法参数、被执行方法和对象）。通知在这些切入点被触发。AOP框架允许开发者以多种方式定义切入点</td>
</tr>
<tr>
<td>引入（Introduction）</td>
<td>添加方法、字段、接口、注解等到被通知的类</td>
</tr>
<tr>
<td>目标对象（Target Object）</td>
<td>包含连接点的对象，也被称作被通知或被代理对象</td>
</tr>
<tr>
<td>AOP代理（AOP Proxy）</td>
<td>AOP框架创建的对象，以目标对象为基础，织入了通知逻辑代理主要包括动态代理、字节码增强两种类型</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">AspectJ基础知识</span></div>
<ol>
<li>AspectJ编译器能识别任何普通的Java代码，可以使用ajc编译.java文件</li>
<li>织入方式：<br />
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td style="width: 100px;">源代码织入</td>
<td>织入器作为编译器的一部分，处理源代码，支持经典语法和注解语法。生成的字节码符合JVM规范，需要使用ajc代替javac</td>
</tr>
<tr>
<td>字节码织入</td>
<td>传递给织入器的是字节码。使用这种方式时，包含编译普通Java类、编译切面，织入3个步骤。</td>
</tr>
<tr>
<td>加载时织入</td>
<td>传递给织入器的是Java类字节码、切面类，以及aop.xml配置文件。</td>
</tr>
</tbody>
</table>
</li>
<li id="joinpoints-exposed-by-aspject">AspectJ暴露的连接点。<strong>只能在这些连接点上应用通知</strong>：<br />
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 80px; text-align: center;"> </td>
<td style="width: 120px; text-align: center;">暴露的连接点</td>
<td style="text-align: center;">代码表现</td>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="2">方法</td>
<td>执行<br />Execution</td>
<td>方法体：该连接点环绕整个方法体的执行过程。这也是Spring AOP唯一支持的接入点类型。通知被织入方法体<br /> <strong>切入点语法：execution(方法签名)</strong></td>
</tr>
<tr>
<td>调用<br />Call</td>
<td>方法调用：该接入点发生在方法被调用时。通知被织入调用者代码处<br /> <strong>切入点语法：call(方法签名)</strong></td>
</tr>
<tr>
<td rowspan="2">构造器</td>
<td>执行<br />Execution</td>
<td>对象构造逻辑：该连接点环绕整个构造器的执行过程<br /> <strong>切入点语法：execution(构造器签名)</strong></td>
</tr>
<tr>
<td>调用<br />Call</td>
<td>对象构造调用<br /> <strong>切入点语法：call(构造器签名)</strong></td>
</tr>
<tr>
<td rowspan="2">字段访问</td>
<td>读访问<br />Read access</td>
<td>读取类或对象的字段<br /> <strong>切入点语法：get(字段签名)</strong></td>
</tr>
<tr>
<td>写访问<br />Read access</td>
<td>写入类或对象的字段<br /> <strong>切入点语法：set(字段签名)</strong></td>
</tr>
<tr>
<td>异常处理</td>
<td>处理器<br />Handler</td>
<td>处理异常的catch块<br /> <strong>切入点语法：handler(类型签名)</strong></td>
</tr>
<tr>
<td rowspan="3">初始化</td>
<td>类初始化<br />Class initialization</td>
<td>类加载，包括静态成员初始化部分<br /> <strong>切入点语法：staticinitialization(类型签名)</strong></td>
</tr>
<tr>
<td>对象初始化<br />Object initialization</td>
<td>在构造器中的对象初始化。包含：从一个父构造器返回，到当前构造器执行完成的部分（不包括调用父构造器的部分）<br /> <strong>切入点语法：initialization(构造器签名)</strong><br /> Spring的@Configurable即为此例 。下面的例子解释了连接点的范围：<br />
<pre class="crayon-plain-tag">public class SavingsAccount extends Account
{
    private boolean isOverdraft;
    private int     minimumBalance;
    //构造器1
    public SavingsAccount( int accountNumber, 
                                 boolean isOverdraft )
    {
        super( accountNumber );
        //对象初始化连接点：构造器1，2
        this.isOverdraft = isOverdraft;
    }
    //构造器2
    public SavingsAccount( int accountNumber )
    {
        //对象初始化连接点：构造器2
        this( accountNumber, false );
        //对象初始化连接点：构造器2
        this.minimumBalance = 25;
    }
}</pre>
</td>
</tr>
<tr>
<td>对象预初始化<br />pre-initialization</td>
<td>在构造器中的对象初始化之前：用的很少，从当前构造器调用，到父构造器调用结束为止<br /> <strong>切入点语法：preinitialization(构造器签名)</strong></td>
</tr>
<tr>
<td>通知</td>
<td>执行<br />Execution</td>
<td>通知的执行：环绕某个通知的整个执行。可以对通知进行通知<br /> <strong>切入点语法：adviceexecution()</strong></td>
</tr>
</tbody>
</table>
</li>
<li>AspectJ切入点声明语法<br />
<pre class="crayon-plain-tag">/**
 * 切入点声明语法，包含5个部分：
 * 访问标识符：例如 public
 * 关键字：pointcut
 * 切入点名称()
 * 切入点类型：例如execution、call，参考：第3点
 * 切入点签名：根据切入点类型不同，可能是类型签名、方法签名、字段签名
 */
public pointcut secureAccess(): execution(* MessageCommunicator.deliver(..));</pre></p>
<p>AspectJ支持仅有切入点名称，而没有类型和签名的切入点，通常使用在抽象切面中。<br /> AspectJ支持匿名切入点，作为通知签名的一部分存在。<br /> AspectJ支持使用 !、 &amp;&amp; 、|| 来作为切入点的运算符</p>
</li>
<li>AspectJ通知定义语法：由<strong>通知声明、切入点定义、通知体三部分</strong>组成<br />
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">组成</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2">整体语法形式：<br />
<pre class="crayon-plain-tag">[@AdviceName("通知的名称")]
[返回值] 通知类型([上下文信息]) [returning|throwing] [throws 通知抛出的异常] : 切入点定义([上下文信息]) {
    通知体
}</pre>
</td>
</tr>
<tr>
<td>通知声明</td>
<td>通知类型可以是：before, after 或 around，其中around需要声明返回值通知声明可以指定通知体可用的上下文信息，包括：执行对象通知声明可以指定通知体可能抛出的异常</td>
</tr>
<tr>
<td>切入点定义</td>
<td>位于冒号之后，任何匹配切入点定义的连接点上都会执行本通知</td>
</tr>
<tr>
<td style="width: 100px;">通知体</td>
<td>可以访问一系列特殊的变量或关键字，例如：proceed、thisJoinPoint、thisJoinPointStaticPart、 thisEnclosingJoinPointStaticPart</td>
</tr>
</tbody>
</table>
</li>
<li>AspectJ支持的通知类型<br />
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;">通知类型</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>Before advice</td>
<td>在连接点执行之前执行，如果抛出异常，那么连接点不被执行</td>
</tr>
<tr>
<td>After advice</td>
<td>在连接点执行之后执行，根据连接点的执行结果，具有3个子类型：After (finally)：在连接点执行之后执行，不论其结果，通知声明语法：<strong>after()</strong>After returning：在连接点执行成功后执行，通知声明语法：<strong>after() returning(&lt;ReturnType returnObject&gt;)</strong>After throwing：在连接点执行失败后执行，通知声明语法：<strong>after() throwing(&lt;ExceptionType exceptionObject&gt;)</strong></td>
</tr>
<tr>
<td>Around advice</td>
<td>环绕连接点的执行过程，具有修改连接点执行上下文的能力，可以用来：
<ol>
<li>在连接点之前/之后添加额外的逻辑，例如性能分析</li>
<li>跳过原先逻辑还执行备选的逻辑，例如缓存。只要不调用proceed()，即跳过</li>
<li>使用try-catch包裹原先逻辑，提供异常处理策略，例如事务管理</li>
</ol>
</td>
</tr>
</tbody>
</table>
</li>
</ol>
<div class="blog_h2"><span class="graybg">AspectJ切入点签名语法详解</span></div>
<div class="blog_h3"><span class="graybg">通配符</span></div>
<p>通配符用于匹配一系列的连接点。</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td> *</td>
<td>匹配点号.范围内的任意数目的字符在类型签名中：表示部分包名或者部分类名在其他地方：表示部分的方法或者字段名</td>
</tr>
<tr>
<td> ..</td>
<td>匹配任意数目的字符，包括任意数量的点号在类型签名中：表示任意直接、间接的子包在方法签名中：表示任意数量的方法参数</td>
</tr>
<tr>
<td> +</td>
<td>作为类型签名的后缀，表示包含任意的子类型</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">类型签名语法</span></div>
<p>这里的类型泛指：类、接口、注解、切面、基本类型<br /> <strong>基本类型签名示例：</strong></p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">签名</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>Account</td>
<td>仅匹配Account类型</td>
</tr>
<tr>
<td>*Account</td>
<td>匹配任何类名以Account结尾的类型</td>
</tr>
<tr>
<td>java.*.Date</td>
<td>匹配java的<strong>直接子包</strong>中的Date</td>
</tr>
<tr>
<td>java..*</td>
<td>匹配java包及其任意子包中的任意类型</td>
</tr>
<tr>
<td>javax..*Model+</td>
<td>匹配java包及其任意子包中的任意以Model结尾的类型，及其子类型</td>
</tr>
</tbody>
</table>
<p><strong>基于注解的类型签名示例：</strong><br /> 由于Java不支持注解的继承，所有注解名后不会出现加号。注意注解必须运行时可见（<pre class="crayon-plain-tag">RetentionPolicy.RUNTIME</pre> ）</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">签名</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>@Secured Account</td>
<td>标注了@Secured注解的Account类型</td>
</tr>
<tr>
<td>@Sensitive *</td>
<td>标注了@Sensitive注解的任何类型</td>
</tr>
<tr>
<td>@Business* Customer+</td>
<td>Customer及其子类型，且标注了Business开头的注解</td>
</tr>
</tbody>
</table>
<p><strong>基于泛型的类型签名示例：</strong></p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">签名</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>Map&lt;Long,Account&gt;</td>
<td>仅仅匹配Map&lt;Long,Account&gt;类型</td>
</tr>
<tr>
<td>*&lt;Account&gt;</td>
<td>任何把Account作为其泛型参数的类型</td>
</tr>
<tr>
<td>Collection&lt;@Sensitive *&gt;</td>
<td>Collection类型，其泛型参数类必须被标注了@Sensitive</td>
</tr>
<tr>
<td>Collection&lt;? extends Account&gt;</td>
<td>Collection类型，其泛型参数类必须是Account或者其子类</td>
</tr>
<tr>
<td>Collection&lt;? super Account&gt;</td>
<td>Collection类型，其泛型参数类必须是Account的父类</td>
</tr>
</tbody>
</table>
<p><strong>联合类型签名示例：</strong></p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">签名</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>!Collection</td>
<td>除了Collection的任何类型</td>
</tr>
<tr>
<td>Collection || Map</td>
<td>Collection或者Map类型</td>
</tr>
<tr>
<td>java.util.RandomAccess+ &amp;&amp; java.util.List+</td>
<td>任何同时实现了这两个接口的子类，例如ArrayList</td>
</tr>
<tr>
<td>!@Secured *</td>
<td>任何没有标注@Secured 的类型</td>
</tr>
<tr>
<td>@Secured @Sensitive *</td>
<td>任何同时标注了@Secured @Sensitive的类型</td>
</tr>
<tr>
<td>@(Secured || Sensitive) *</td>
<td>任何标注了@Secured @Sensitive之一的类型</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">方法和构造器签名语法</span></div>
<p>构造器签名与方法类似，但是：</p>
<ol>
<li>由于构造器没有返回值，因此不得在签名中指定返回值</li>
<li>由于构造器不能为静态，故不得添加static关键字</li>
<li>由于构造器没有名称，必须使用new作为其名称部分</li>
</ol>
<p><a href="/wp-content/uploads/2011/04/method-pattern-format.jpg"><img src="https://blog.gmem.cc/wp-content/uploads/2011/04/method-pattern-format.jpg" alt="" /></a><br /> <strong>基本方法签名示例：</strong></p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">签名</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>public void Account.set*(*)</td>
<td>Account类中，包含单个参数、返回类型为void、以set开头的公共方法</td>
</tr>
<tr>
<td>public void Account.*()</td>
<td>Account类中，任何返回类型为void、没有参数的公共方法</td>
</tr>
<tr>
<td>public * Account.*()</td>
<td>Account类中，任何没有参数的公共方法</td>
</tr>
<tr>
<td>public * Account.*(..)</td>
<td>Account类中，包含任意参数（包括0参）的公共方法</td>
</tr>
<tr>
<td>* Account.*(..)</td>
<td><span style="color: #000000;">Account类中，包含任意参数（包括0参）的方法</span></td>
</tr>
<tr>
<td>* *.*(..)* *(..)</td>
<td>任意方法</td>
</tr>
<tr>
<td>!public * Account.*(..)</td>
<td>任何Account类的非公共方法</td>
</tr>
<tr>
<td>* *(..) throws SQLException</td>
<td>任何声明抛出SQLException的方法</td>
</tr>
<tr>
<td>* Account+.*(..)</td>
<td>Account及其子类的任何方法</td>
</tr>
<tr>
<td>* java.io.Reader.read(char[],..)</td>
<td>java.io.Reader类的read方法，第一个参数必须为char[]</td>
</tr>
<tr>
<td>* javax..*.add*Listener(EventListener+)</td>
<td>javax的任意子包中的类的方法，必须以add开头、Listener结尾，且包含唯一的参数EventListener类型及其子类型</td>
</tr>
<tr>
<td>* java.io.PrintStream.printf(String,Object...)</td>
<td>java.io.PrintStream的printf方法，第一个参数为字符串，第二个参数为Object...</td>
</tr>
<tr>
<td>Account AccountService.*(..)</td>
<td>AccountService类中任何返回AccountService的方法</td>
</tr>
<tr>
<td>public Account.new()</td>
<td>匹配Account类的0参公共构造器</td>
</tr>
</tbody>
</table>
<p><strong>基于注解的方法签名示例：</strong></p>
<p>注意注解必须运行时可见（<pre class="crayon-plain-tag">RetentionPolicy.RUNTIME</pre> ）</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 250px; text-align: center;">签名</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>@Secured * *(..)</td>
<td>任何标注了@Secured的方法</td>
</tr>
<tr>
<td>@Secured @Transactional * *(..)</td>
<td><span style="color: #000000;">任何同时标注了@</span><span style="color: #000000;">Secured、@Transactional 的方法</span></td>
</tr>
<tr>
<td>@(Secured || Transactional) * *(..)</td>
<td><span style="color: #000000;">任何标注了@</span><span style="color: #000000;">Secured或者@Transactional 的方法</span></td>
</tr>
<tr>
<td>(@Sensitive *) *(..)</td>
<td>任何返回值类型上标注了@Sensitive的方法</td>
</tr>
<tr>
<td>* (@BusinessEntity *).*(..)</td>
<td>任何标注了@BusinessEntity的类的任何方法</td>
</tr>
<tr>
<td>* *(@RequestParam (*))</td>
<td>任何包含了单个参数，且参数上标注了@RequestParam 的方法，例如：void show(@RequestParam Long id)</td>
</tr>
<tr>
<td>* *(@Sensitive *)* *((@Sensitive *))</td>
<td>任何包含了单个参数，且参数的类型上标注了@RequestParam 的方法，例如：void create(ClassAnnotatedWithSensitive obj)</td>
</tr>
<tr>
<td>* *(@RequestParam(@Sensitive *))</td>
<td><span style="color: #000000;">void create(@RequestParam </span><span style="color: #000000;">ClassAnnotatedWithSensitive </span><span style="color: #000000;">obj</span><span style="color: #000000;">)</span></td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">字段签名语法</span></div>
<p>字段签名中，使用get表示读字段，set表示写字段：<br /> <img src="https://blog.gmem.cc/wp-content/uploads/2011/04/field-pattern-format.jpg" alt="" /><br /> <strong>字段签名示例：</strong></p>
<p>注意注解必须运行时可见（<pre class="crayon-plain-tag">RetentionPolicy.RUNTIME</pre> ）</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">签名</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>private double Account.balance</td>
<td>Account类的私有double类型的balance字段</td>
</tr>
<tr>
<td>* Account.*</td>
<td>Account类的任何字段</td>
</tr>
<tr>
<td>* Account+.*</td>
<td>Account类及其子类的任何字段</td>
</tr>
<tr>
<td>@Sensitive * *</td>
<td>字段上标注了@Sensitive的任何字段</td>
</tr>
<tr>
<td>(@Sensitive *) *.*</td>
<td>字段的类型上标注了@Sensitive的任何字段</td>
</tr>
<tr>
<td>* (@Sensitive *).*</td>
<td>标注了@Sensitive的类的任何字段</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">AspectJ切入点的实现</span></div>
<p>AspectJ提供几种切入点指示器（designators），配合上面所述的切入点签名，即组成切入点。<br /> 切入点通过两种方式与连接点进行匹配：</p>
<ol>
<li>类型限定的切入点：直接映射到某个类型的连接点，参考<a href="#joinpoints-exposed-by-aspject">AspectJ暴露的连接点</a>一节中的“切入点语法”部分</li>
<li>无类型的切入点：根据指定的信息，来选择特定的连接点。这些信息可以是：连接点上下文的运行时类型、控制流，或者此法作用域（lexical scope）</li>
</ol>
<div class="blog_h3"><span class="graybg">类型限定的切入点</span></div>
<p>匹配：指定类型和签名的连接点<br /> Spring：仅支持execution类型<br /> 静态确定：是</p>
<div class="blog_h3"><span class="graybg">无类型的切入点</span></div>
<p>不去限定连接点的类型，还是通过若干种规则去匹配多种连接点。</p>
<p>Spring虽然仅仅支持execution一种类型的连接点，但是却支持多种方式来选择它们</p>
<p><strong>基于控制流的切入点</strong><br /> 这一类的切入点匹配 <strong>处于其他切入点的控制流之中</strong> 的连接点。这句话比较难以理解，以贷款业务为例，假设Account.debit()方法调用Account.getBalance()进行余额查询，那么，可以说：getBalance在debit的控制流之中。类似的，字段访问、异常处理，也可以处于某个切入点的控制流之中。<br /> Spring不支持这一类切入点，不能静态确定（需要运行时判断）<br /> 包含两种切入点类型：cflow、cflowbelow，后者不包括启动控制流的连接点本身</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 300px; text-align: center;">切入点</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>cflow(execution(* Account.debit(..)))</td>
<td>匹配所有这样的连接点：位于Account的任何debit方法的控制流之中，包括debit方法本身</td>
</tr>
<tr>
<td>cflowbelow(execution(* Account.debit(..)))</td>
<td>匹配所有这样的连接点：位于Account的任何debit方法的控制流之中，不包括debit方法本身</td>
</tr>
<tr>
<td>cflow(execution(@Transactional * *(..)))</td>
<td>匹配所有位于配置@Transactional方法的控制流之中的任何连接点</td>
</tr>
<tr>
<td>cflow(transacted())</td>
<td>匹配切入点transacted所选择的任何连接点的控制流之中的连接点</td>
</tr>
</tbody>
</table>
<p>下面以事务管理的场景为例，来说明控制流切入点的用法：</p>
<pre class="crayon-plain-tag">package cc.gmem.aj.cflow;
public class Account
{
    //两个方法均具有事务注解，但是，我们需要在“最外层”来启动事务
    //需要忽略内层的事务注解
    @Transactional
    public void debit()
    {
        getBalance();
    }
    @Transactional
    public void getBalance()
    {
    }
}</pre><br />
<pre class="crayon-plain-tag">public aspect TransactionAspect
{
    //匹配所有标注了@Transactional的方法执行
    private pointcut transacted() : execution(@Transactional * *(..));
    //匹配这样的@Transactional方法：不在@Transactional方法的所确定的控制流的内部
    private pointcut topLevelTransacted() : transacted() &amp;&amp; !cflowbelow(transacted());

    Object around() : topLevelTransacted() {
        System.out.println( "启动事务" );
        Object ret = proceed();
        System.out.println( "结束事务" );
        return ret;
    }
}</pre>
<p><strong>基于词法结构的切入点</strong><br /> 匹配：在指定类型、方法、构造器内的连接点<br /> Spring：支持within()，不支持withincode()<br /> 可以静态确定<br /> 包含两种切入点类型：within(类型签名)、withincode(构造器签名|方法签名)</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">切入点</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>within(Account)</td>
<td>Account类，及其嵌套类中的任何连接点</td>
</tr>
<tr>
<td>within(Account+)</td>
<td>Account类（或者子类），及其嵌套类中的任何连接点</td>
</tr>
<tr>
<td>within(@javax.persistence.Entity *)</td>
<td>标注了的@Entity类，及其嵌套类中的任何连接点</td>
</tr>
<tr>
<td>withincode(* Account.debit(..))</td>
<td>Account的debit方法中的任何连接点</td>
</tr>
</tbody>
</table>
<p><strong>执行对象切入点</strong><br /> 根据<strong>运行时对象类型</strong>来选择连接点。并且，可以收集执行对象——<strong>双重功能</strong>。</p>
<p>包含两种类型：this(&lt;Type or ObjectIdentifier&gt;)、target(&lt;Type or ObjectIdentifier&gt;)，前者匹配this引用为指定类型的连接点；后者匹配方法调用target为指定类型的连接点。</p>
<p>该类切入点<strong>不支持类型通配，也不支持泛型</strong>。该类切入点<strong>不会匹配任何静态方法的执行连接点</strong>。</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">切入点</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>this(Account)</td>
<td>任何连接点，只要表达式 this instnaceof Account为真，即匹配</td>
</tr>
<tr>
<td>target(Account)</td>
<td>任何（通常是方法调用类型）连接点，只要被调用的方法所属对象 instanceof Account，即匹配</td>
</tr>
</tbody>
</table>
<p>注意区别：<br /> execution(* Account.*(..)) 匹配Account类的任何静态、成员方法<br /> execution(* *.*(..))  &amp;&amp; this(Account)：匹配Account及其子类的任何成员方法<br /> <strong>参数切入点</strong><br /> 该类切入点根据<strong>连接点的参数对象的运行时类型</strong>来匹配。并且，可以收集匹配的参数对象。<br /> Spring支持此类切入点。无法静态确定。<br /> 所谓参数对象，根据连接点不同，含义也不同：</p>
<ol>
<li>对于方法、构造器连接点，参数对象即方法参数</li>
<li>对于异常处理连接点，参数对象即被处理的异常</li>
<li>对于字段写入连接点，参数对象即被写入的值</li>
</ol>
<p>该类切入点的形式为：args(Type or ObjectIdentifier, ..)</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">切入点</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>args(Account, .., int)</td>
<td>任何方法或者构造器，第一个参数的运行时类型为Account或其子类型，最后一个参数的运行时类型为int</td>
</tr>
<tr>
<td>args(RemoteException)</td>
<td>任何具有单个RemoteException类型参数的连接点。</td>
</tr>
</tbody>
</table>
<p><strong>基于注解的切入点</strong></p>
<p>注意：注解本身被标注的注解影响AOP行为：</p>
<ol>
<li>@Retention(RetentionPolicy.RUNTIME)：只有设置为运行时保留，才能在运行时进行匹配性判断</li>
<li>@<span style="color: #000000;">Inherited：只有标注了此注解，子编程元素（类、方法）才能继承父元素上标注的注解</span></li>
</ol>
<p>AspectJ支持根据类型、方法、字段所标注的注解来匹配连接点</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 350px; text-align: center;">切入点</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>@this(TypePattern or ObjectIdentifier)</td>
<td>任何连接点，只要this的类上具有TypePattern指定的注解注意：如果注解是@Inherited的，父类上有指定注解即可</td>
</tr>
<tr>
<td>@target(TypePattern or ObjectIdentifier)</td>
<td>任何连接点，只要target的类上具有TypePattern指定的注解</td>
</tr>
<tr>
<td>@args(TypePattern or ObjectIdentifier, ..)</td>
<td>任何连接点，只要参数的类上具有TypePattern指定的注解</td>
</tr>
<tr>
<td>@within(TypePattern or ObjectIdentifier)</td>
<td>任何连接点，只要在具有TypePattern指定的注解的类型的词法作用域内</td>
</tr>
<tr>
<td>@withincode(TypePattern or ObjectIdentifier)</td>
<td>任何连接点，只要在具有TypePattern指定的注解的构造器或方法的词法作用域内</td>
</tr>
<tr>
<td>@annotation(TypePattern or ObjectIdentifier)</td>
<td>任何连接点，只要目标上具有指定的注解目标的含义：
<ol>
<li>对于方法、构造器、通知执行连接点：目标为对应的程序元素</li>
<li>对于字段访问、异常处理连接点：目标为被访问的字段或者异常</li>
<li>对于初始化、预初始化连接点：目标为匹配的起始调用(first-called)构造器</li>
<li>对于静态初始化连接点：目标为被初始化的类</li>
</ol>
</td>
</tr>
</tbody>
</table>
<p><strong>条件检查切入点</strong><br /> 此类切入点在连接点上的一些条件检查。通常和其它切入点联合使用</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">切入点</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>if(debug)</td>
<td>任何debug静态字段（位于切面类）设置为true的连接点</td>
</tr>
<tr>
<td>if(System.currentTimeMillis() &gt; triggerTime)</td>
<td>任何发生在triggerTime以后的连接点</td>
</tr>
<tr>
<td>if(circle.getRadius() &lt; 5)</td>
<td>任何连接点，只要circle的radius小于5。circle必须是被收集的上下文对象，或者切面的静态字段。</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">AspectJ切面类基本结构</span></div>
<p>本段代码示意经典的AspectJ语法：</p>
<pre class="crayon-plain-tag">package cc.gmem.aj;

//切面的声明
public aspect SecurityAspect
{

    private Authenticator auth = new Authenticator();

    //切入点的声明
    pointcut secureAccess(): execution(* MessageCommunicator.deliver(..));
    //通知声明：针对secureAccess切入点的before通知
    before() : secureAccess() {
        System.out.println( "Checking and authenticating user" );
        auth.doAuthenticate();
    }
}</pre>
<p>本段代码示意基于注解的AspectJ语法：<br /> 基于注解的语法，可以作为普通Java类编译，并且使用LTW（加载时织入）机制，在类被加载到JVM中时进行织入。</p>
<pre class="crayon-plain-tag">package cc.gmem.aj;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class SecurityAspect
{

    private Authenticator auth = new Authenticator();

    @Pointcut ( "execution(* cc.gmem.aj.MessageCommunicator.deliver(..))" )
    public void secureAccess()
    {
    }

    @Before ( "secureAccess()" )
    public void secure()
    {
        System.out.println( "Checking and authenticating user" );
        auth .doAuthenticate();
    }
}</pre>
<div class="blog_h2"><span class="graybg">AspectJ切面示例</span></div>
<p>环绕通知的简单例子，注意proceed()的使用：</p>
<pre class="crayon-plain-tag">public aspect SecurityAspect
{
    private Authenticator auth = new Authenticator();

    pointcut secureAccess(): execution(* MessageCommunicator.deliver(..));

    Object around() : secureAccess() {
        long start = System.nanoTime();
        //伪关键字proceed，用于继续执行被通知的目标方法
        Object ret = proceed();
        //thisJoinPointStaticPart是通知可用变量之一，可以获取连接点的静态信息，例如方法名
        System.out.println( thisJoinPointStaticPart.getSignature() + " took " + ( end - start ) + " nanoseconds" );
        return ret;
    }
}</pre>
<p>上下文收集的简单例子：</p>
<pre class="crayon-plain-tag">package cc.gmem.aj;

import java.sql.Connection;
import java.sql.SQLException;

public aspect ConnectionAspect
{
    //匹配Connection的任何抛出SQLException方法的调用
    //被调用（target）的Connection对象收集为connection变量。
    pointcut connectionOperation( Connection connection )//独立定义的切入点，必须使用这种参数声明来传递上下文信息给通知
        : call(* Connection.*(..) throws SQLException) &amp;&amp; target(connection);

    Object around( Connection connection ) : connectionOperation(connection) {//传递了上下文
        long startTime = System.nanoTime();
        Object ret = proceed();
        //thisJoinPoint是通知体可用的变量之一
        System.out.println( "Operation " + thisJoinPoint + " on " + connection + " took " + ( System.nanoTime() - startTime ) );
        return ret;
    }
}</pre>
<p>上下文收集注解的例子：</p>
<pre class="crayon-plain-tag">before(Secured secured ) : 
    //匹配任何方法执行
    execution(* *(..)) 
    //匹配连接点目标————即方法本身————上具有@secured注解的连接点
    &amp;&amp; @annotation(secured)
{
    //注解可以像普通对象一样被使用
    checkPermission(secured.permission());
}</pre>
<p>&nbsp;</p>
<p>上下文收集的另外一个例子，注意传递给目标的参数被收集，可被通知体使用：</p>
<pre class="crayon-plain-tag">package cc.gmem.aj;

public aspect AccountAspect
{

    boolean processOverdraft( Account account, float amount )
    {
        return true;
    }

    void around( Account account, float amount ) throws InsufficientBalanceException
    //匹配任何对Account.debit(float) throws InsufficientBalanceException方法的调用
        : call(void Account.debit(float) throws InsufficientBalanceException)
        &amp;&amp; target(account) &amp;&amp; args(amount)//收集的上下文信息作为局部变量使用
    {
        try
        {
            proceed( account, amount );//传递给目标方法的参数，可以任意修改
        }
        catch ( InsufficientBalanceException ex )
        {
            //进行透支处理
            if ( !processOverdraft( account, amount ) )
            {
                throw ex;
            }
        }
    }
}</pre>
<div class="blog_h2"><span class="graybg">进行加载时织入（LTW）</span></div>
<p>在classpath的META-INF/aop.xml中，声明需要织入的切面：</p>
<pre class="crayon-plain-tag">&lt;aspectj&gt;
    &lt;aspects&gt;
        &lt;aspect name="cc.gmem.aj.SecurityAspect"/&gt;
    &lt;/aspects&gt;
&lt;/aspectj&gt;</pre>
<p>通过指定JVM启动参数-javaagent来启用LTW：</p>
<pre class="crayon-plain-tag">-javaagent:%ASPECTJ_HOME%\lib\aspectjweaver.jar</pre>
<p>如果使用Spring，可以通过配置，避免修改JVM启动参数</p>
<div class="blog_h2"><span class="graybg">AspectJ横切构造（crosscutting construct）</span></div>
<div class="blog_h3"><span class="graybg">通用横切构造</span></div>
<p>AspectJ支持连接点、切入点、切面等构造。</p>
<div class="blog_h3"><span class="graybg">动态横切构造：修改行为</span></div>
<p>AspectJ的动态横切构造依赖于“通知”实现。通知包括Before、After、Around几种。</p>
<p><b>收集连接点上下文</b></p>
<p>连接点上下文包括两种类型：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td> 连接点牵涉的对象</td>
<td>切入点：this(), target(), args()可以用于收集相应的对象可以使用类型（Type）或者对象名称（ObjectIdentifier）两种方式来收集，对于后者，必须在通知声明处声明相应的对象</td>
</tr>
<tr>
<td>连接点关联的注解</td>
<td>切入点：@this(), @target(), @args(), @annotation(),@within(), @withincode()可用于收集相应的注解</td>
</tr>
</tbody>
</table>
<p><strong>通过反射访问连接点上下文</strong></p>
<p>作为备选方式，AspectJ提供了基于反射机制的访问静态（不会随着连接点执行而变化的）、动态连接点上下文信息的方法。这种方式可以完全替换上一条进行动态上下文收集，但是具有以下缺点：</p>
<ol>
<li>性能较为低下</li>
<li>缺少静态语法检查</li>
<li>比较笨重</li>
</ol>
<p>通过AspectJ提供的通知体可用的特殊变量来使用这种反射API：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 200px; text-align: center;">变量</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>thisJoinPoint</td>
<td>变量类型为JoinPoint。可以访问目标对象、执行对象、参数的信息，包括相应的注解信息。可以通过getStaticPart()方法访问静态信息</td>
</tr>
<tr>
<td>thisJoinPointStaticPart</td>
<td>变量类型为JoinPoint.StaticPart。可以访问源码位置、连接点类型、连接点签名。</td>
</tr>
<tr>
<td>thisEnclosingJoinPointStaticPart</td>
<td>变量类型为JoinPoint.StaticPart。用于访问包围的连接点静态上下文，所谓“包围的连接点”依连接点类型而不同，例如：
<ol>
<li>对于方法调用，包围连接点是caller的执行</li>
<li>对于异常处理，包围连接点是try-catch块所在方法</li>
</ol>
</td>
</tr>
</tbody>
</table>
<p><strong>两种访问连接点上下文的方式的对照表</strong></p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">切入点语法</td>
<td style="text-align: center;"> 反射方式</td>
</tr>
</thead>
<tbody>
<tr>
<td>pointcut pc(Account acc) : this(acc)</td>
<td>Account acc = (Account)thisJoinPoint.getThis()</td>
</tr>
<tr>
<td>pointcut pc(Account acc): target(acc)</td>
<td>Account acc = (Account)thisJoinPoint.getTarget()</td>
</tr>
<tr>
<td>pointcut pc(Account acc,Customer cust): args(acc, cust)</td>
<td>Object[] arguments = thisJoinPoint.getArgs();<br /> Account acc = (Account)arguments[0];<br /> Customer cust = (Customer)arguments[1];</td>
</tr>
<tr>
<td>poincut pc(Secure sec) : @this(annot);</td>
<td>Secure sec = thisJoinPoint.getThis().getClass().<br /> getAnnotation(Secure.class)</td>
</tr>
<tr>
<td>poincut pc(Secure sec) : @target(sec);</td>
<td>Secure sec = thisJoinPoint.getTarget().getClass().<br /> getAnnotation(Secure.class);</td>
</tr>
<tr>
<td>pointcut pc(Secure sec, Transactional tx) : @args(sec, tx);</td>
<td>Object[] arguments = thisJoinPoint.getArgs();<br /> Secure sec = arguments[0].getClass().<br /> getAnnotations(Secure.class);<br /> Transactional tx = arguments[1].getClass().<br /> getAnnotations(Transactional.class);</td>
</tr>
<tr>
<td>poincut pc(Sensitive sens) : @annotation(sec);</td>
<td>FieldSignature sig =<br /> (FieldSignature)thisJoinPointStaticPart.getSignature();<br /> Sensitive sens = sig.getField().getAnnotation(Sensitive.class);</td>
</tr>
<tr>
<td>pointcut pc(Secure sec) : @within(sec);</td>
<td>thisJoinPointStaticPart.getSignature().<br /> getDeclaringType().getAnnotation(Secure.class);</td>
</tr>
<tr>
<td>pointcut pc(Secure sec) : @withincode(sec);</td>
<td>MethodSignature sig =<br /> (MethodSignature)thisJoinPointStaticPart.getSignature();<br /> Secure sec = sig.getMethod().getAnnotation(Secure.class);</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">静态横切构造：修改结构</span></div>
<p><strong>静态横切总是在动态横切之前应用</strong>。</p>
<p>静态横切构造由：<strong>跨类型声明（inter-type declaration ，ITD，亦称“引入introduction)”）</strong>和<strong>织入时声明（weave-time declarations）</strong>组成<br /> <strong>跨类型声明（引入）</strong><br /> 可以修改类、接口、或者切面的静态结构，例如增加一个字段，添加一个接口。在一个切面中，声明其他类型的结构，故曰ITD。下面是一个例子：</p>
<pre class="crayon-plain-tag">package cc.gmem.aj;

public aspect TrackingAspect
{

    //声明MessageCommunicator实现接口AccessTracked，效果和Java标准语法一样
    declare      parents: MessageCommunicator implements AccessTracked;

    //声明AccessTracked类型的一个字段，所有它的子类型自动获取此字段
    private long AccessTracked.lastAccessedTime;

    //声明AccessTracked类型的两个方法，所有它的子类型自动继承这些方法
    public void AccessTracked.updateLastAccessedTime()
    {
        lastAccessedTime = System.currentTimeMillis();
    }

    public long AccessTracked.getLastAccessedTime()
    {
        return lastAccessedTime;
    }

    before( AccessTracked accessTracked ) : //声明了一个通知局部变量accessTracked
        execution(* AccessTracked+.*(..)) //AccessTracked子类型的任何方法
        &amp;&amp; !execution(* AccessTracked.*(..))//除了AccessTracked本身的方法
        &amp;&amp; this(accessTracked)//this对象收集为accessTracked变量
    {
        accessTracked.updateLastAccessedTime();
    }

    private static interface AccessTracked
    {
    }
}</pre>
<p><strong>成员引入的规则</strong></p>
<ol>
<li>只能引入private、public成员，前者只能被切面类访问，后者可以被系统中所有类访问</li>
<li>如果是private的，多个切面可以引入同名的成员</li>
<li>切面可以引入字段、函数、构造器到类或者接口。特别的，可以引入方法的实现到接口——缺省实现</li>
<li>如果切面引入一个和类中同名的方法，那么，类中的那个方法被保留</li>
<li>成员引入只能针对一个类型</li>
</ol>
<p><strong>接口缺省实现的例子</strong></p>
<pre class="crayon-plain-tag">package cc.gmem.aj;

public interface Nameable
{
    public void setName( String name );

    public String getName();
    //缺省实现
    static aspect Impl
    {
        private String Nameable.name;

        public void Nameable.setName( String name )
        {
            this.name = name;
        }

        public String Nameable.getName()
        {
            return this.name;
        }
    }
}</pre>
<p><strong>使用ITD来实现Java的Mixin机制</strong></p>
<p>Mixin是一种程序构造，允许在已有类中混入特定的逻辑，Java语言没有语言级别的机制，下面的例子示意了如何使用AspectJ进行混入</p>
<pre class="crayon-plain-tag">//一个标记性接口，用于混入功能
public interface BeanSupport {}
//一个简单的POJO，需要混入：属性变更监听的功能
public class Customer implements BeanSupport
{
    private String address;
    public String getAddress()
    {
        return address;
    }
    public void setAddress( String address )
    {
        this.address = address;
    }
}</pre>
<p>通过下面的代码，即可为Customer或者任何实现了BeanSupport的类型混入属性变更的功能，而没有任何的侵入性。</p>
<pre class="crayon-plain-tag">public aspect BeanMakerAspect
{

    private PropertyChangeSupport BeanSupport.propertyChangeSupport;
    public void BeanSupport.addPropertyChangeListener( PropertyChangeListener listener )
    {
        propertyChangeSupport.addPropertyChangeListener( listener );
    }
    public void BeanSupport.removePropertyChangeListener( PropertyChangeListener listener )
    {
        propertyChangeSupport.removePropertyChangeListener( listener );
    }
    pointcut beanCreation( BeanSupport bean )
    //匹配BeanSupport及其子类型的初始化连接点
    : initialization(BeanSupport+.new(..)) &amp;&amp; this(bean);

    pointcut beanPropertyChange( BeanSupport bean, Object newValue )
    //匹配BeanSupport及其子类型的任何Setter方法的执行
    : execution(void BeanSupport+.set*(*))
    &amp;&amp; args(newValue) &amp;&amp; this(bean);
    //BeanSupport初始化成功后，创建一个propertyChangeSupport字段的实例
    after( BeanSupport bean ) returning : beanCreation(bean) {
        bean.propertyChangeSupport = new PropertyChangeSupport( bean );
    }
    //Setter调用后，发布相应的事件
    void around( BeanSupport bean, Object newValue )  : beanPropertyChange(bean, newValue) 
    {
        String methodName = thisJoinPointStaticPart.getSignature().getName();
        String propertyName = Introspector.decapitalize( methodName.substring( 3 ) );
        Object oldValue = getPropertyValue( bean, propertyName );
        proceed( bean, newValue );
        bean.propertyChangeSupport.firePropertyChange( propertyName, oldValue, newValue );
    }
}</pre>
<p><strong>修改类层次结构</strong></p>
<p>AspectJ提供两种需要类层次的形式：</p>
<pre class="crayon-plain-tag">declare parents : [TypePattern] implements [InterfaceList];
declare parents : [TypePattern] extends [Class or InterfaceList];
//举例：所有实体类实现BeanSupport接口
public aspect EntityBeanParticipationAspect {
    declare parents: @Entity * implements BeanSupport;
}
//hasMethod、hasField，任何包含指定模式方法或者字段的类：
declare parents: hasmethod(@Observed * *(*)) implements BeanSupport;</pre>
<p><strong>引入注解</strong></p>
<p>AspectJ支持为字段、类、方法等添加注解</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 50%; text-align: center;">语法形式</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>declare @method: &lt;Method signature pattern&gt;:&lt;Annotation&gt;;</td>
<td>引入注解给AccountService的任何方法，例如：declare @method: * AccountService.*(..):<br /> @Transactional(Propagation.Required);</td>
</tr>
<tr>
<td>declare @constructor: &lt;Constructor signature pattern&gt;:&lt;Annotation&gt;;</td>
<td>引入注解给构造器，例如：declare @constructor: AccountService+.new():<br /> @ConfigurationOnly;</td>
</tr>
<tr>
<td>declare @field: &lt;Field signature pattern&gt;:&lt;Annotation&gt;;</td>
<td>引入注解给字段，例如：declare @field: * MissileInformation.*:<br /> @Classified;</td>
</tr>
<tr>
<td>declare @type: &lt;Type signature pattern&gt;:&lt;Annotation&gt;;</td>
<td>引入注解给类型，例如：declare @type: banking..* :<br /> @PrivacyControlled;</td>
</tr>
</tbody>
</table>
<p><b>简化异常处理</b></p>
<p>允许不强制捕获受查异常，声明方式如下：</p>
<pre class="crayon-plain-tag">//这里声明不需要强制捕获的异常
declare soft : &lt;ExceptionTypePattern&gt; : &lt;pointcut&gt;;</pre>
<p><strong>织入时声明——警告或者错误信息</strong></p>
<p>可以在织入时，根据一定的模式来生成错误或者警告信息，举例：</p>
<pre class="crayon-plain-tag">//当doAuthenticate方法在SecurityAspect以外调用时，生成警告
declare      warning: 
    call(void Authenticator.doAuthenticate()) //切入点：方法被调用的地方，与execution不同
    &amp;&amp; !within(SecurityAspect)  : //切入点，不在SecurityAspect内
        
        "Authentication should be performed only by SecurityAspect";</pre>
<div class="blog_h2"><span class="graybg">在Spring中使用AspectJ</span></div>
<div id="spring-aop-with-aspectj-config" class="blog_h3"><span class="graybg">使用Spring AOP，结合AspectJ风格的切面声明</span></div>
<p>这种场景下，本质上还是Spring基于JDK动态代理的AOP机制，只是借用AspectJ的语法。</p>
<pre class="crayon-plain-tag">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
    "&gt;
    &lt;!-- 提示Spring自动为目标对象创建代理 --&gt;
    &lt;aop:aspectj-autoproxy /&gt;
    &lt;!-- 声明普通Bean --&gt;
    &lt;bean id="messageCommunicator" class="cc.gmem.aj.MessageCommunicator" /&gt;
    &lt;!-- 声明切面Bean，注意，必须使用注解语法定义切面 --&gt;
    &lt;bean id="securityAspect" class="cc.gmem.aj.SecurityAspect" /&gt;
&lt;/beans&gt;</pre>
<div class="blog_h3"><span class="graybg">使用spring-aspects切面库</span></div>
<p>可以基于AspectJ，而不是Spring AOP来实现：事务管理、缓存、任务调度等常用AOP场景，以避免Spring AOP的固有缺陷。<br /> 特别是使用@Configurable注解来支持非Spring Bean的依赖注入，必须基于AspectJ完成。</p>
<pre class="crayon-plain-tag">&lt;!-- 支持非受管对象（Spring Bean）的依赖注入和生命周期注解 --&gt;
&lt;context:spring-configured /&gt;
&lt;!-- 支持基于AspectJ的事务管理 --&gt;
&lt;tx:annotation-driven transaction-manager="txManager" mode="aspectj" /&gt;
&lt;!-- 支持基于AspectJ的缓存机制--&gt;
&lt;cache:annotation-driven cache-manager="cacheManager" mode="aspectj" /&gt;
&lt;!-- 支持基于AspectJ的任务调度和执行 --&gt;
&lt;task:annotation-driven  scheduler="taskScheduler" executor="taskExecutor" mode="aspectj" /&gt;</pre>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/aspectj-study-note">AspectJ编程学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/aspectj-study-note/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
