Spring Aop Step-By-Step 学习笔记

第8章 Spring AOP 首先介绍了Spring AOP,包括Spring AOP的概述和Spring AOP的术语;然后讲解了Spring AOP的实现机制,包括JDK动态代理和CGLib动态代理;接着讲解了基于XML的AOP实现,并使用案例的方式实现了基于XML文件的AOP;最后讲解了基于注解的AOP实现。......... 阅读详情
最近由于工作需要,要求掌握关于 Spring 方面的东西。所以花了两个星期的时间来学习 Spring 的基本知识,主要包括 Ioc 和 Aop 两方面。
本文为笔者的 Spring 在 Aop 方面的学习笔记,主要结合了 Spring In Action 第三章 和 Spring-Reference 第五章 为学习向导。根据自己的理解和书中的实例来一步一步完成对于在 Spring 中 Aop 方面的编程。其中基础部分 Ioc 需要读者自己参考资料了解,本文将不做描述。
说明:我将尽量缩短程序长度,在程序部分将减少注释说明,重点要读者自己根据上下文和程序结果理解体会,具体 api 信息请读者自己参考 Spring-api 文档和相关资料。
一.    准备工作:
 
1.  开发环境:
l             适合人群:
                  要了解 Spring Ioc ,对 Spring- Aop 可以不了解或者仅仅熟悉 Aop 概念,未参与 Spring Aop 开发实战的初学者。同时也希望高手对于本文的不足或理解错误之处给予指点,谢谢。
l             开发环境:
JDK 1.4_2
l             开发工具:
Eclipse 3.12 (未采用任何插件,主要是为初学者熟悉和理解 xml 文档的配置)
l             所需组件:
Spring-Framework-1.2.8
下载地址:
 
2.    建立工程:
   首先用 Eclpse 建立一个普通 java 项目,导入 jar 文件到编译环境中,如下:
a)             Spring.jar 为 Spring 的核心 jar 文件,必须;
b)             Commons-loggin.jar 日志文件,必须;
c)             Cglib.jar 动态代理文件,不是必须(本文需要);
d)             Jak-oro.jar 使用 Perl 和 Awk 正则表达式进行文本解析工具,不是必须(本文需要);
建立工程如下:

好了,下来我们开始我们的 Spring-aop 之旅;
 
二.  Spring -Aop 入门
 
AOP 全名 Aspect-oriented programming 。 Spring framework 是很有前途的 AOP 技术。作为一种非侵略性的,轻型的 AOP framework ,你无需使用预编译器或其他的元标签,便可以在 Java 程序中使用它。这意味着开发团队里只需一人要对付 AOP framework ,其他人还是像往常一样编程。
关键性概念:
1)          Advice 是代码的具体实现,例如一个实现日志记录的代码。
2)          Pointcut 是在将 Advice 插入到程序的条件。
3)           advisor 是把 pointcut 和 advice 的组合在一起装配器。
 
图例:
你的程序可能如上,现在要在三个流程上同时加入日志控制和权限控制,如下:
 

 你的程序可能如上,现在要在三个流程上同时加入日志控制和权限控制,如下:

         其中拿日志为例,日志控制和流程之间的穿插点处叫做连接点( Joinpoint ),而 Advice 就是我们日志处理的具体代码, Pointcut 就是定义一个规则,对三个和业务有关的连接点进行过滤和匹配(例如我们对于业务 1 不做日志处理)。 Advisor 就是将符合的规则的剩下的两个连接点和具体的日志记录代码组合在一起。
 
三.  Spring-Aop 前置通知、后置通知、环绕通知、异常通知实现
 
我以 Spring In Action 提供的例子进行二次改造,完成我们自己的流程。业务流程很简单,顾客到商店买东西,店员根据顾客的需要给于顾客提供服务。实现方法前插入,方法后插入,环绕,异常四种。
 
       代码:
          建立一个用户类;
public class Customer {
     private String name = " 悠~游!";
     public String getName() {
          return name;
     }
}
三个产品
public class Cheese {
   public String toString(){
         return " 奶酪!";
   }
}
public class Pepper {
     public String toString(){
          return " 胡椒粉!";
     }
}
public class Squish {
     public String toString(){
          return " 果酱!";
     }
}
          建立一个接口;
public interface KwikEMart {
     Squish buySquish(Customer customer) throws KwikEMartException;
     Pepper buyPepper(Customer customer) throws KwikEMartException;
     Cheese buyCheese(Customer customer) throws KwikEMartException;
}
 
实现这个接口,我们实现三个方法,买奶酪,买胡椒粉,买果酱;
public class ApuKwikEMart implements KwikEMart {
     private boolean cheeseIsEmpty = false;
 
     private boolean pepperIsEmpty = false;
 
     private boolean squishIsEmpty = false;
 
     public Cheese buyCheese(Customer customer) throws NoMoreCheeseException{
 
          if (cheeseIsEmpty) {
               throw new NoMoreCheeseException();
          }
 
          Cheese s = new Cheese();
          System.out.println("-- 我想买:" + s);
          return s;
 
     }
 
     public Pepper buyPepper(Customer customer) throws NoMorePepperException{
 
          if (pepperIsEmpty) {
               throw new NoMorePepperException();
          }
 
          Pepper s = new Pepper();
          System.out.println("-- 我想买:" + s);
          return s;
 
     }
 
     public Squish buySquish(Customer customer) throws NoMoreSquishException{
 
          if (squishIsEmpty) {
               throw new NoMoreSquishException();
          }
 
          Squish s = new Squish();
          System.out.println("-- 我想买:" + s);
          return s;
 
     }
 
     public void setCheeseIsEmpty(boolean cheeseIsEmpty) {
          this.cheeseIsEmpty = cheeseIsEmpty;
     }
 
     public void setPepperIsEmpty(boolean pepperIsEmpty) {
          this.pepperIsEmpty = pepperIsEmpty;
     }
 
     public void setSquishIsEmpty(boolean squishIsEmpty) {
          this.squishIsEmpty = squishIsEmpty;
     }
 
}
环绕通知的实现,必须实现invoke方法,通过调用invoke.proceed()手工调用对象方法:
public class OnePerCustomerInterceptor implements MethodInterceptor {
    
     private Set customers=new HashSet();
 
     public Object invoke(MethodInvocation invoke) throws Throwable {
         
          Customer customer=(Customer)invoke.getArguments()[0];
          if(customers.contains(customer)){
               throw new KwikEMartException("One per customer.");
          }
         
          System.out.println(" 店员:"+customer.getName() + " ,Can I help you ?");
          Object squishee=invoke.proceed(); // 手工调用对象方法;
          System.out.println(" 店员:OK! " + customer.getName() + ".give you! " );
         
          customers.add(squishee);
 
          return squishee;
     }
}
前置通知的实现;
public class WelcomeAdvice implements MethodBeforeAdvice {
 
     public void before(Method method, Object[] args, Object target) throws Throwable {
         
          Customer customer = (Customer) args[0];
          System.out.println(" 店员::Hello " + customer.getName() + " . How are you doing?");
 
     }
}
public class Customer {
     private String name = " 悠~游!";
     public String getName() {
          return name;
     }
}
后置通知实现;
public class ThankYouAdvice implements AfterReturningAdvice {
 
     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
         
          Customer customer = (Customer) args[0];
          System.out.println(" 店员:Thank you " + customer.getName() + " . Come again! " );
 
     }
}
系统异常处理通知实现;
public class KwikEmartExceptionAdvice implements ThrowsAdvice {
 
     public void afterThrowing(NoMoreSquishException e) {
          System.out.println(" 系统:NoMoreSquisheesException异常截获了: " + e.getMessage());
     }
     public void afterThrowing(NoMoreCheeseException e) {
          System.out.println(" 系统:NoMoreCheeseException异常截获了: " + e.getMessage());
     }
     public void afterThrowing(NoMorePepperException e) {
          System.out.println(" 系统:NoMorePepperException异常截获了: " + e.getMessage());
     }
}
自定义的异常接口;
public class KwikEMartException extends Exception {
 
     private static final long serialVersionUID = -3962577696326432053L;
 
     String retValue = "KwikEMartException 异常!";
 
     public KwikEMartException(String name) {
          retValue = name;
     }
     public KwikEMartException() {
 
     }
     public String getMessage() {
          return retValue;
     }
 
}
没有更多的奶酪异常;
public class NoMoreCheeseException extends KwikEMartException {
     private static final long serialVersionUID = -3961123496322432053L;
 
     String retValue = "NoMoreCheeseException 异常!";
 
     public NoMoreCheeseException() {
          super();
     }
 
     public NoMoreCheeseException(String name) {
          super(name);
     }
 
     public String getMessage() {
 
          return retValue;
     }
}
没有更多的胡椒粉异常;
public class NoMorePepperException extends KwikEMartException {
     private static final long serialVersionUID = -3961234696322432053L;
 
     String retValue = "NoMorePepperException 异常!";
 
     public NoMorePepperException() {
          super();
     }
 
     public NoMorePepperException(String name) {
          super(name);
     }
 
     public String getMessage() {
 
          return retValue;
     }
}
没有更多的果酱异常;
public class NoMoreSquishException extends KwikEMartException {
     private static final long serialVersionUID = -3121234696322432053L;
 
     String retValue = "NoMoreSquishException 异常!";
 
     public NoMoreSquishException() {
          super();
     }
 
     public NoMoreSquishException(String name) {
          super(name);
     }
 
     public String getMessage() {
 
          return retValue;
     }
}
运行实例类;
         
public class RunDemo {
 
               public static void kwikEMart() {
 
               ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/kwikemart.xml");
 
                    // 如果你想通过类来引用这个的话,就要用到CGLIB.jar了,同时在代理工厂里面设置:
                    //<property name="proxyTargetClass" value="true" />
                    KwikEMart akem = (KwikEMart) context.getBean("kwikEMart");
    
                    try {
                         akem.buySquish(new Customer());
                         akem.buyPepper(new Customer());
                         akem.buyCheese(new Customer());
                    } catch (KwikEMartException e) {
                         // 异常已经被截获了,不信你看控制台!~;
                    }
               }
 
               public static void main(String[] args) {
                    kwikEMart();
               }
}
     Xml 文件配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
 
<beans>
     <bean id="kwikEMartTarget" class="demo.ApuKwikEMart">
          <!--
               把这里注释去掉的话,程序调用的时候测试异常通知;
               <property name="cheeseIsEmpty">
                    <value>true</value>
               </property>
               <property name="pepperIsEmpty">
                    <value>true</value>
               </property>
               <property name="squishIsEmpty">
                    <value>true</value>
               </property>
          -->
     </bean>
 
     <!-- 方法调用前通知 -->
     <bean id="welcomeAdvice" class="demo.advice.WelcomeAdvice" />
     <!-- 方法调用后通知 -->
     <bean id="thankYouAdvice" class="demo.advice.ThankYouAdvice" />
     <!-- 环绕调用通知 -->
     <bean id="onePerCustomerInterceptor" class="demo.advice.OnePerCustomerInterceptor" />
     <!-- 异常调用通知 -->
     <bean id="kwikEmartExceptionAdvice" class="demo.advice.KwikEmartExceptionAdvice" />
    
     <bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="proxyInterfaces" value="demo.KwikEMart" />
          <property name="interceptorNames">
               <list>
                   
                         <value>welcomeAdvice</value>
                         <value>thankYouAdvice</value>
                         <value>onePerCustomerInterceptor</value>
                         <value>kwikEmartExceptionAdvice</value>
                   
               </list>
          </property>
          <property name="target">
               <ref bean="kwikEMartTarget" />
          </property>
     </bean>
 
</beans>
     这个例子东西很多,不过每个类的代码都不大。如果你对 org.springframework.aop.framework.ProxyFactoryBean 不是很了解的话可以看我下篇尾处的介绍。 读清楚之后,我们运行RunDemo 类,查看控制台结果,如下:
 
店员::Hello 悠~游! . How are you doing?
店员:悠~游! ,Can I help you ?
--我想买:果酱!
店员:OK! 悠~游!.give you!
店员:Thank you 悠~游! . Come again!
店员::Hello 悠~游! . How are you doing?
店员:悠~游! ,Can I help you ?
--我想买:胡椒粉!
店员:OK! 悠~游!.give you!
店员:Thank you 悠~游! . Come again!
店员::Hello 悠~游! . How are you doing?
店员:悠~游! ,Can I help you ?
--我想买:奶酪!
店员:OK! 悠~游!.give you!
店员:Thank you 悠~游! . Come again!
 
    我们将 kwikEMartTarget 里面的注释去掉,测试异常实现,如下:
    
店员::Hello 悠~游! . How are you doing?
店员:悠~游! ,Can I help you ?
系统:NoMoreSquisheesException异常截获了: NoMoreSquishException 异常!
     好好理解一下,我就不废话了,我们进行下一节。
 
 
 
四.  Spring-Aop 之 Pointcut +advice+Advisor 实现
 
我们修改我们的xml文档后如下:
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
 
     <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
 
     <!-- 环绕调用通知 -->
     <bean id="onePerCustomerInterceptor" class="demo.advice.OnePerCustomerInterceptor" />
 
     <!-- 使用NameMatchMethodPointcut -->
     <bean id="nameMatchfilterPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
          <property name="mappedName">
               <!--
                    buy.* 以buy开头的方法;
               -->
               <value>buy*</value>
          </property>
     </bean>
 
     <!-- 使用Perl5RegexpMethodPointcut -->
     <bean id="regexpFilterPointcut" class="org.springframework.aop.support.Perl5RegexpMethodPointcut">
          <property name="pattern">
               <!--
                    .*buy.+ 以buy开头的方法;
                    .*buyS.+ 以buyS开头的方法;
               -->
               <value>.*suy.+</value>
          </property>
     </bean>
 
     <bean id="runDemofilterPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
          <property name="pointcut">
               <ref bean=" nameMatchfilterPointcut" />
          </property>
          <property name="advice">
               <ref bean="onePerCustomerInterceptor" />
          </property>
     </bean>
     <bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="proxyInterfaces" value="demo.KwikEMart" />
          <property name="interceptorNames">
               <list>
                    <value>runDemofilterPointcutAdvisor</value>
               </list>
          </property>
          <property name="target">
               <ref bean="kwikEMartTarget" />
          </property>
     </bean>
 
</beans>
 
运行,结果如下:
店员:悠~游! ,Can I help you ?
--我想买:果酱!
店员:OK! 悠~游!.give you!
店员:悠~游! ,Can I help you ?
--我想买:胡椒粉!
店员:OK! 悠~游!.give you!
店员:悠~游! ,Can I help you ?
--我想买:奶酪!
        店员:OK! 悠~游!.give you!
 
在这里简单说明一下xml文档: nameMatchfilterPointcut 和regexpFilterPointcut 是我们自己定义好规则的Pointcut。nameMatchfilterPointcut 根据mappedName来设置过滤规则, regexpFilterPointcut则是用pattern来设置过滤规则。runDemofilterPointcutAdvisor 则将我们的 Pointcut 和advice组合在一起。
读者可以自己修改runDemofilterPointcutAdvisor的pointcut来切换不同的Pointcut。如果需要RegexpMethodPointcut 的子类的实现,必须要oro包支持。(注:RegexpMethodPointcut有俩个子类的实现,JdkRegexpMethodPointcut和Perl5RegexpMethodPointcut)。
     但是,如果我们想让我们的Advisor同时实现多个Pointcut+advice怎么办呢?利用Spring In Action里面的实例,我们来自己实现我们的Pointcut。
 
    代码:
 
 
public class MyUnionPointcut implements Pointcut {
    
     private Pointcut delegate;
 
     public ClassFilter getClassFilter() {
          return getDelegate().getClassFilter();
     }
 
     private Pointcut getDelegate() {
          if (delegate == null) {
               throw new AopConfigException("No pointcuts have been configured.");
          }
          return delegate;
     }
 
     public MethodMatcher getMethodMatcher() {
          return getDelegate().getMethodMatcher();
     }
 
     public void setPointcuts(List pointcuts) {
 
          if (pointcuts == null || pointcuts.size() == 0) {
               throw new AopConfigException("Must have at least one Pointcut.");
          }
          delegate = (Pointcut) pointcuts.get(0);
 
          for (int i = 1; i < pointcuts.size(); i++) {
               Pointcut pointcut = (Pointcut) pointcuts.get(i);
               delegate = Pointcuts.union(delegate, pointcut);
          }
 
     }
}
 
其实就是继承Pointcut类,实现getMethodMatcher()方法即可,接下来看我们把那两个Pointcut组合成一个,当其中一个Pointcut满足的时候就返回true,调用我们的Advice。
 
在xml中,加入下面代码:
 
 
     <bean id="myUnionPointcut" class="demo.utils.MyUnionPointcut">
          <property name="pointcuts">
               <list>
               <!-- 这里说明一下:动态切入点和静态切入点集合在一起的时候好像有问题? -->
                    <ref bean="nameMatchfilterPointcut" />
                    <ref bean="regexpFilterPointcut" />
               </list> 
          </property>
     </bean>
修改runDemofilterPointcutAdvisor的pointcut来加入我们组合好的Pointcut。
 
     <bean id="runDemofilterPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
          <property name="pointcut">
               <ref bean= ”myUnionPointcut" />
          </property>
          <property name="advice">
               <ref bean="onePerCustomerInterceptor" />
          </property>
     </bean>
 
同时在运行前,读者可以自己修改两个pointcut的匹配方法,来匹配更多的可选项。同时可以参考的一个类是org.springframework.aop.support.UnionPointcut,它实现两个pointcut的联合。如果读者想实现更加灵活的匹配,需要自己来定义自己的pointcut。(如第一个pointcut交叉第二个pointcut,联合第三个pointcut),交叉的工具类为ComposablePointcut。
运行的结果请读者自己试验。这个时候您可能在想,这些pointcut都是Spring自己的实现,我们能否自己来定义我们自己规则的pointcut呢?当然可以!~
代码:
/**
 *
 * 自己定义的静态切入点
 * 满足条件是:当传入的数字大于1块钱的时候才可以;
 *
 * @author 悠~游
 * @since 2006-06-22
 * @link www.uusam.com
 */
public class MyPointcut extends StaticMethodMatcherPointcut implements Serializable {
 
     private static final long serialVersionUID = -101281038294508751L;
 
     private int money = 0;
 
     /**
      * 实现方法,业务逻辑为:根据输入的钱数和动作(必须是以buy开头的方法),来确定是否有钱购买商品,买完之后去掉商品的价格;
      */
     public boolean matches(Method method, Class targetClass) {
          if (method.getName().indexOf("buyCheese") == 0 && money >= 100) {
               money -= 100;
               return true;
          } else if (method.getName().indexOf("buyPepper") == 0 && money >= 5) {
               money -= 5;
               return true;
          } else if (method.getName().indexOf("buySquish") == 0 && money >= 10) {
               money -= 10;
               return true;
          }
          System.out.println(" 门卫:你要买的东西太贵,你的钱 "+money+" 太少!~ ,取消服务!");
          return false;
     }
 
     public void setMoney(int money) {
          this.money = money;
     }
 
}
 
这个就是我们自己定义的静态Pointcut,主要实现自己的matches方法。看看如何加入到我们的XML文档中:
 
     <!-- 使用自定义的切入点 -->
     <bean id="myPointcut" class="demo.pointcut.MyPointcut">
          <property name="money">
               <value>100</value>
          </property>
     </bean>
 
很简单不是么?我们定义一个数字,就是用户的money,进入商店时候兜里的钱^_^。同样修改我们的myUnionPointcut里面的pointcuts,加入我们的pointcut。
 
    
<bean id="myUnionPointcut" class="demo.utils.MyUnionPointcut">
          <property name="pointcuts">
               <list>
                    <!— 上面两个要设置成不通过哦,或者索性就去掉先。 -->
                    <ref bean="nameMatchfilterPointcut" />
                    <ref bean="regexpFilterPointcut" />
<ref bean="myPointcut" />
               </list> 
          </property>
     </bean>
    
当上面两个Pointcut定义的规则不通过的时候,程序开始校验我们的myPointcut。运行,结果如下:
店员:悠~游! ,Can I help you ?
--我想买:果酱!
店员:OK! 悠~游!.give you!
店员:悠~游! ,Can I help you ?
--我想买:胡椒粉!
店员:OK! 悠~游!.give you!
门卫:你要买的东西太贵,你的钱 85 太少!~ , 取消服务!
--我想买:奶酪!//服务员没了...
    
     好了,是不是我们想要的结果呢?呵呵。
     同时,Spring 提供动态Pointcut。关于动态的说明我就不在熬述了,我们这里只关心具体Spring带给我们的具体实现方法,具体应用请读者自己斟酌使用。
    
 
     <!-- 定制动态接入点,来判断当前线程堆栈中是否有demo.RunDemo这个类; -->
     <bean id="runDemoPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
          <constructor-arg>
               <value>demo.RunDemo</value>
          </constructor-arg>
     </bean>
     修改下面的引用我们的动态Pointcut;
<bean id="myUnionPointcut" class="demo.utils.MyUnionPointcut">
          <property name="pointcuts">
<list>
     <ref bean=" runDemoPointcut " />
         </list> 
    </property>
</bean>
 
     运行,结果如下:
店员:悠~游! ,Can I help you ?
--我想买:果酱!
店员:OK! 悠~游!.give you!
店员:悠~游! ,Can I help you ?
--我想买:胡椒粉!
店员:OK! 悠~游!.give you!
店员:悠~游! ,Can I help you ?
--我想买:奶酪!
店员:OK! 悠~游!.give you!
    
     动态切入点是根据当前堆栈信息进行方法匹配的一种规则,读者可以自己修改demo.RunDemo,如java.lang.Integer,来看看结果。
 
--我想买:果酱!
--我想买:胡椒粉!
--我想买:奶酪!
    
     到这里能够读下来已经很不容易了,呵呵。还是站起来走动一下吧,接下来我们将搞定其他的一些东东。
 
五. Spring-Aop 引入的介绍
 
    下面我们介绍一种通知“引入”,关于引入,如同它的名字一样,给对象添加方法和属性。呵呵,好厉害吧。它是通过CBLIB来动态生成类的,所以自己用的时候别忘了加载这个包。
    
     代码:
     购物时候放东西的包包;
public interface CustomerBag {
     void addBag(Object obj);
 
     void clean();
 
     int getCount();
}
 
我们要给别的对象类添加的Mixin,嘿嘿。
public class CustomerMixin extends DelegatingIntroductionInterceptor implements CustomerBag {
 
     private static final long serialVersionUID = 5296015143432822715L;
    
     private ArrayList bag = new ArrayList();
 
     public void addBag(Object obj) {
          bag.add(obj);
     }
 
     public void clean() {
          bag = new ArrayList();
     }
 
     public ArrayList getBag() {
          return bag;
     }
 
     public int getCount() {
          return bag.size();
     }
 
}
 
     我们的xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
    
     <bean id="customer" class="demo.Customer" singleton="false" />
 
     <bean id="customerMixin" class="demo.CustomerMixin" singleton="false" />
 
 
     <bean id="customerMixinAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor"
          singleton="false">
          <constructor-arg>
               <ref bean="customerMixin" />
          </constructor-arg>
     </bean>
 
     <bean id="customerBean" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="proxyTargetClass" value="true" />
          <property name="singleton" value="false" />
          <property name="interceptorNames">
               <list>
                    <value>customerMixinAdvisor</value>
               </list>
          </property>
          <property name="target">
               <ref bean="customer" />
          </property>
     </bean>
 
</beans>
 
可以看到singleton="false"处处可见,因为我们要每个新的对象都有自己引入的状态,不可能只有一个对象来维持,那个我们肯定是不希望的。
修改我们的RunDemo类,添加一个方法:
     /**
      * 创建引用通知;
      */
     public static void customer() {
 
          ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/customer.xml");
 
          // 这个类是有CGLIB动态生成的;
          Customer bag = (Customer) context.getBean("customerBean");
          CustomerBag bag2 = (CustomerBag) bag;
          bag2.addBag(new Object());
 
          System.out.println(bag.getName());
          System.out.println(bag2.getCount());
     }
 
          在main中调用这个方法,运行,结果如下:
              
               悠~游!
1
 
          在这里我要说明一下,关于引入这个通知的使用我仅仅是看了一眼,具体的例子可能有不恰当之处还请高手们指点。
 
六. Spring-Aop 之 BeanNameAutoProxyCreator
 
BeanNameAutoProxyCreator 看其名,大概知道其意。根据bean的名字自动匹配拦截代理,让我们看看它能带来什么?
代码:
public class PerformanceThresholdInterceptor implements MethodInterceptor {
 
     private final long thresholdInMillis;
 
     PerformanceThresholdInterceptor(long time) {
          thresholdInMillis = time;
 
     }
 
     public Object invoke(MethodInvocation invocation) throws Throwable {
         
          System.out.println(" 开始测试时间.");
          long t = System.currentTimeMillis();
          Object o = invocation.proceed();
          t = System.currentTimeMillis() - t;
          if (t > thresholdInMillis) {
               System.out.println(" 警告:调用的方法所耗费的时间超过预警时间(" + thresholdInMillis + " 微秒)");
          }
          System.out.println(" 测试时间结束.");
          return o;
     }
}
这个又是自定义的,呵呵。我们继承MethodInterceptor这换类,实现我们自己的方法过滤器。具体要实现的功能就是检验我们要调用的方法,和OnePerCustomerInterceptor这个类一样。
接下来是我们的xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
     <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
    
     <bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">
          <constructor-arg>
               <value>5000</value>
          </constructor-arg>
     </bean>
 
     <bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
          <property name="beanNames">
               <list>
                    <value>*Target</value>
               </list>
          </property>
          <property name="interceptorNames">
               <value>performanceThresholdInterceptor</value>
          </property>
     </bean>
 
</beans>
 
在main方法中加入我们的方法:
   /**
    * 创建beanNameAutoProxyCreator动态代理;
    */
   public static void beanNameProxy() {
 
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/beanNameProxy.xml");
 
        KwikEMart akem = (KwikEMart) context.getBean("kwikEMartTarget");
        try {
             akem.buyCheese(new Customer());
        } catch (KwikEMartException e) {
             e.printStackTrace();
        }
   }
 
     运行我们的例子,结果如下:
    
开始测试时间.
--我想买:奶酪!
测试时间结束.
    
     看到了么?Spring aop自动寻找Bean的名字为* Target 的类,进行方法过滤。呵呵,可能你会说这个有什么用?自己写不也一样么?其实如果系统变得庞大的话,自己配置也是十分耗费精力的。
 
七. Spring-Aop DefaultAdvisorAutoProxyCreator
 
     接下来我们将介绍更加强大的一个代理器:DefaultAdvisorAutoProxyCreator。
     DefaultAdvisorAutoProxyCreator 和BeanNameAutoProxyCreator不同的是,DefaultAdvisorAutoProxyCreator只和Advisor 匹配,所以我们写一个Advisor到xml文档中去。
     XML 文档如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
 
     <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
     <bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">
          <constructor-arg>
               <value>5000</value>
          </constructor-arg>
     </bean>
 
     <!-- 使用RegexpMethodPointcutAdvisor来匹配切入点完成个一个Advisor; -->
     <bean id="regexpFilterPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
          <property name="pattern">
               <!--    
                    匹配的名字为方法名;
               -->
               <value>.*buy.*</value>
          </property>
          <property name="advice">
               <ref bean="performanceThresholdInterceptor"/>
          </property>
     </bean>
 
     <bean id="defaultAdvisorAutoProxyCreator"
     class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
 
</beans>
    
     添加下面方法调用main方法中去:
/**
* 创建defaultAdvisorAutoProxyCreator动态代理;
*/
   public static void defaultAdvisorProxy() {
 
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/defaultAdvisorProxy.xml");
 
        KwikEMart akem = (KwikEMart) context.getBean("kwikEMartTarget");
        try {
             akem.buyCheese(new Customer());
        } catch (KwikEMartException e) {
             e.printStackTrace();
        }
   }
     运行,结果如下:
         
开始测试时间.
--我想买:奶酪!
测试时间结束.
 
 
八. Spring-Aop TargetSources 介绍
 
1. 可热交换的目标源
 
可热交换的目标源主要是在你程序运行中切换目标对象,而此时调用者引用的对象也会自动切换。具体的概念你可以参考Spring-Reference关于它的介绍,我们主要在程序中体会它给我们带来的改变。
修改我们的xml成为下面的样子:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
 
<beans>
 
     <bean id="kwikEMartTarget" class="demo.ApuKwikEMart" ></bean>
    
     <bean id="swapApuKwikEMart" class="demo.SwapApuKwikEMart" singleton="false"></bean>
    
     <bean id="onePerCustomerInterceptor" class="demo.advice.OnePerCustomerInterceptor" />
 
     <bean id="nameMatchfilterPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
          <property name="mappedName">
               <value>buy*</value>
          </property>
     </bean>
 
     <bean id="runDemofilterPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
          <property name="pointcut">
               <ref bean="nameMatchfilterPointcut" />
          </property>
          <property name="advice">
               <ref bean="onePerCustomerInterceptor" />
          </property>
     </bean>
 
     <bean id="swappable" class="org.springframework.aop.target.HotSwappableTargetSource">
          <constructor-arg><ref local="kwikEMartTarget"/></constructor-arg>
     </bean>
 
     <bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="proxyInterfaces" value="demo.KwikEMart" />
          <property name="interceptorNames">
               <list>
                    <value>runDemofilterPointcutAdvisor</value>
               </list>
          </property>
          <property name="targetSource">
               <ref bean="swappable" />
          </property>
     </bean>
 
</beans>
 
代码:
切换后的对象
public class SwapApuKwikEMart implements KwikEMart {
     private boolean cheeseIsEmpty = false;
 
     private boolean pepperIsEmpty = false;
 
     private boolean squishIsEmpty = false;
 
     public Cheese buyCheese(Customer customer) throws KwikEMartException {
 
          if (cheeseIsEmpty) {
               throw new NoMoreCheeseException();
          }
 
          Cheese s = new Cheese();
          System.out.println("-- 我不是ApuKwikEMart,我想买:" + s);
          return s;
 
     }
 
     public Pepper buyPepper(Customer customer) throws KwikEMartException {
 
          if (pepperIsEmpty) {
               throw new NoMorePepperException();
          }
 
          Pepper s = new Pepper();
          System.out.println("-- 我不是ApuKwikEMart,我想买:" + s);
          return s;
 
     }
 
     public Squish buySquish(Customer customer) throws KwikEMartException {
 
          if (squishIsEmpty) {
               throw new NoMoreSquishException();
          }
 
          Squish s = new Squish();
          System.out.println("-- 我不是ApuKwikEMart,我想买:" + s);
          return s;
 
     }
 
     public void setCheeseIsEmpty(boolean cheeseIsEmpty) {
          this.cheeseIsEmpty = cheeseIsEmpty;
     }
 
     public void setPepperIsEmpty(boolean pepperIsEmpty) {
          this.pepperIsEmpty = pepperIsEmpty;
     }
 
     public void setSquishIsEmpty(boolean squishIsEmpty) {
          this.squishIsEmpty = squishIsEmpty;
     }
 
}
添加下面代码的引用到我们的main中。
 /**
  * 热源切换;
  */
 public static void swapKwikEMart() {
 
      ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/swapKwikmart.xml");
 
      // 如果你想通过类来引用这个的话,就要用到CGLIB.jar了,同时在代理工厂里面设置:
      //<property name="proxyTargetClass" value="true" />
      KwikEMart akem = (KwikEMart) context.getBean("kwikEMart");
     
      try {
           akem.buySquish(new Customer());
           akem.buyPepper(new Customer());
           akem.buyCheese(new Customer());
      } catch (KwikEMartException e) {
           // 异常已经被截获了,不信你看控制台!~;
      }
     
      HotSwappableTargetSource swap = (HotSwappableTargetSource) context.getBean("swappable");
      swap.swap(context.getBean("swapApuKwikEMart"));
     
      try {
           akem.buySquish(new Customer());
           akem.buyPepper(new Customer());
           akem.buyCheese(new Customer());
      } catch (KwikEMartException e) {
           // 异常已经被截获了,不信你看控制台!~;
      }
 }
 
运行,结果如下:
 
店员:悠~游! ,Can I help you ?
--我想买:果酱!
店员:OK! 悠~游!.give you!
店员:悠~游! ,Can I help you ?
--我想买:胡椒粉!
店员:OK! 悠~游!.give you!
店员:悠~游! ,Can I help you ?
--我想买:奶酪!
店员:OK! 悠~游!.give you!
店员:悠~游! ,Can I help you ?
--我不是ApuKwikEMart,我想买:果酱!
店员:OK! 悠~游!.give you!
店员:悠~游! ,Can I help you ?
--我不是ApuKwikEMart,我想买:胡椒粉!
店员:OK! 悠~游!.give you!
店员:悠~游! ,Can I help you ?
--我不是ApuKwikEMart,我想买:奶酪!
                            店员:OK! 悠~游!.give you!
 
可以看到,我们切换后的对象已经被置换了。注意 singleton="false" ,通常情况下需要设置为false,以保证Spring在必要的时候可以创建一个新的目标实例。
 
2. 支持池的目标源
使用支持目标池的源提供了一种和无状态 session Ejb 类似的编程方式,在无状态的 Session Ejb 中,维护了一个相同实例的池,提供从池中获取可用对象的方法。
这次我们用到了 Commons - pool 这个包,同时在运行时候还需要 commons-collections.jar, 需要把它们加载到环境变量中。
xml 文件如下:
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
 
<beans>
 
     <bean id="kwikEMartTarget" class="demo.ApuKwikEMart" singleton="false"></bean>
 
     <bean id="commonsPool" class="org.springframework.aop.target.CommonsPoolTargetSource">
          <property name="targetBeanName">
               <value>kwikEMartTarget</value>
          </property>
          <property name="maxSize">
               <value>10</value>
          </property>
     </bean>
 
     <bean id="methodInvokingFactoryBeanAdvisor"
          class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
          <property name="targetObject">
               <ref bean="commonsPool" />
          </property>
          <property name="targetMethod">
               <value>getPoolingConfigMixin</value>
          </property>
 
     </bean>
     <bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="proxyInterfaces" value="demo.KwikEMart" />
          <property name="interceptorNames">
               <list>
                    <value>methodInvokingFactoryBeanAdvisor</value>
               </list>
          </property>
          <property name="targetSource">
               <ref bean="commonsPool" />
          </property>
     </bean>
 
</beans>
 
同时,我们还需要 添加下面代码的引用到我们的main中。
代码:
 
       /**
        * 调用池对象;
        */
       public static void getCommonPoolObject() {
 
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/kwikemart.xml");
 
              KwikEMart akem = (KwikEMart) context.getBean("kwikEMart");
              try {
                     akem.buyCheese(new Customer());
              } catch (KwikEMartException e) {
                     e.printStackTrace();
              }
             
              PoolingConfig pool=(PoolingConfig)akem;
              System.out.println(" 池的大小为: "+pool.getMaxSize());
       }
 
运行,结果如下:
 
--我想买:奶酪!
池的大小为:10
 
同时在我们的控制台里可以看到这句话:
信息: Creating Commons object pool
你可以得到对象,也可以销毁对象。但是必须你的目标对象实现了 DisposableBean 接口,重写销毁的方法。然后通过下面方法调用:
 
CommonsPoolTargetSource comPool = (CommonsPoolTargetSource) context.getBean("commonsPool");
 
try {
       comPool.destroyObject(akem);
} catch (Exception e) {
       e.printStackTrace();
              }
销毁池则用:
comPool.destroy() ;
             
 
九. Spring-Aop 相关及其他
 
其他相关的比较重要的是org.springframework.aop.framework.ProxyFactoryBean 类,几乎我们上篇都用到了这个类,简单介绍一下:
 

ProxyFactoryBean

属性
描述
target
代理的目标对象
proxyInterfaces
代理实现的接口
interceptorNames
在应用到的目标对象上添加的Advice的名字,可以是拦截器、advisor或者其他通知类型的名字(顺序很重要哦)
 
其他还有singleton,proxyTargetClass。
singleton :每次调用getBean()的时候返回一个新的实例,例如我们使用引入的时候,有状态的bean要设置为false哦。
     proxyTargetClass :是否代理目标类,而不是实现接口。只能在使用CBLIB的时使用。
    
proxyTargetClass 重点说一下,什么意思呢?白话说的意思就是:如果你不设置proxyInterfaces这个,就必须设置这个方法,并且方法值为True。就是告诉CBLIB你要动态创建一个代理类来引用我们的目标。
         
在 Spring-Reference 中,提到了事务代理,我想那个相对于持久化处理时候在了解比较合适。 对于元数据的支持,因为我还没有精力读到哪里。所以这个暂且搁下,有兴趣的读者可以自己查阅参考。
 
非常感谢你能读完正篇文章,将不足的地方通过邮件传递给我,我将尽快改正。最后我希望,能够让每一个读过的人都有所获得,让我们享受Spring给我们带来的乐趣吧。
 
   
   
    参考资料;
               Spring-Reference 中文版 第五章 Spring 之面向方面编程  
                                                                     http://www.jactiongroup.net/reference/html/
        
Spring AOP 中文教程                                http://spring.jactiongroup.net/viewtopic.php?t=478
    
Spring In Action 中文版 第三章
    
AOP 入門
    
其他:
全文源码及word教程下载:点击下载
Struts2+Spring+Hibernate step by step 10 ssh整合之修改用户 注:本系列文章部分内容来自王健老师编写ssh整合开发教程 本部分展示一次修改多行数据 第一步:修改users.jsp文件如下: 阅读详情

相关推荐

目标检测——布匹缺陷检测数据集

结构瑕疵指的是布料本身的缺陷,包括嵌结、抽纱、错纱、断纱、预缩等问题,这些问题通常是在布料生产过程中出现的。而质量瑕疵则是指布料在使用过程中出现的问题,如污渍、断裂、鼓囊、针眼等,这些问题可能由生产过程中的结构瑕疵导致,也可能是在运输、存放和使用过程中引起的。布匹瑕疵如缺纬、断纬、粗纬、松纬、缺经、断经、粗经、筘痕、污点、破损等,若未得到及时有效的检测,这些瑕疵产品可能会流向市场,导致消费者的不满和退货,严重影响企业的声誉和品牌形象。织疵包括缺经、缺纬、跳花、弓纱、错纱、厚薄段、油污渍等;

zzjlhlcd的博客 612

Spring Aop Step-By-Step 学习笔记(上)

Spring Aop Step-By-Step 学习笔记(上)最近由于工作需要,要求掌握关于Spring 方面的东西。所以花了两个星期的时间来学习Spring的基本知识,主要包括 Ioc和Aop两方面。本文为笔者的Spring 在Aop方面的学习笔记,主要结合了Spring In Action 第三章和 Spring-Reference 第五章为学习向导。根据自己的理解和书中的实例来一

518

在MCUXpresso上通过J-link烧写KW45

背景: KW45B是nxp 的ble npi产品,其使用的IDE为MCUXpressso或者IAR,MCUXpressso有一些bug,但是由于MCUXpressso阅读查找代码相对IAR容易,所以我经常使用的MCUXpressso进行开发。当然IAR也有其优势,比如编译、烧写速度相对MCUXpressso更快,是比较通用的一个平台,而MCUXpressso是NXP独有的。 Kw45有两种烧写方式,一是使用MCUlink,二是使用Jlink。NXP ble 产品线提供的IDE资料里有最新的15.0版本的

weixin_41889258的博客 2859

Spring Aop Step-By-Step 学习笔记(下)

Spring Aop Step-By-Step 学习笔记(下) 悠~游  yysam@yeah.net  QQ:63433688 五.Spring-Aop 引入的介绍     下面我们介绍一种通知“引入”,关于引入,如同它的名字一样,给对象添加方法和属性。呵呵,好厉害吧。它是通过CBLIB来动态生成类的,所以自己用的时候别忘了加载这个包。          代码:

夜雨 758

博客系统 - 系统简介与首页设计

用Bootstrap实现手机端的博客导航栏效果。

m0_53450409的博客 1238

VisionPro动态坐标系构建:CogFixtureTool与CogFixtureNPointToNPointTool实战解析

本文深入解析了VisionPro中动态坐标系构建的核心技术,重点对比了CogFixtureTool与CogFixtureNPointToNPointTool的原理与应用。通过实战案例,阐述了如何利用坐标跟随(Fixturing)技术解决工业视觉检测中因零件位置偏移导致的测量不准问题,实现从“固定”到“随动”的思维跃迁,从而构建稳定、精准的检测程序。

weixin_29207439的博客 565

Step by Step into Spring (AOP)

1.AOPIOC容器是Spring的基础,而AOP面向切面编程(Aspect-Oriented Programming)则是Spring作为一个开发平台实现模块的体现,其将业务代码和一些公用的功能相分离,使得用户在开发过程中不用考虑这些公用功能,如:一些日志记录、事务控制等。 本篇我们将如下组织:先介绍AOP的一些基础知识,然后介绍AOP实现的几种方式,其次介绍Jdk代理模式,最后再介绍AOP的实

CWeeYii的专栏 539

Disk Drill 使用教程

Disk Drill只需单击几下,即可恢复USB闪存驱动器上已删除的数据,包括丢失的照片,文档和其他文件类型。Disk Drill是真正的多合一应用程序,可在Mac上恢复闪存驱动器。Disk Drill将自动应用最佳的笔式驱动器恢复算法来恢复Mac数据。 USB闪存驱动器是一种传输和存储信息的好方法,但是如果错误地丢失或删除了存储在其中的文件,会发生什么呢?当您需要Mac的闪存驱动器数据恢复软件时,Disk Drill是您的最佳选择。Disk Drill将扫描您的USB闪存驱动器(也称为笔式驱动器)并查找

zjj778899的博客 1万+

Spring AOP Step-by-step(1)

一: 概念 Aspect,常译为“方面”,是对施加于不同Class实例的相同问题域的抽象。&lt;o:p&gt;&lt;/o:p&gt; 二: 参与者&lt;o:p&gt;&lt;/o:p&gt; (1) Pointcut: ”方面”的切点--用来决定是否执行Advice的谓词 (2) Advice: 对”方面”的处理&lt;o:p&gt;&lt;/o:p&gt; (3) Advisor: ...

xinyu2006的技术专栏 160

VSCode配置C/C++开发环境:从零安装MinGW-w64并运行第一个C程序

在Windows系统上搭建C语言开发环境时,很多初学者混淆编辑器、编译器与调试器的分工,导致配置过程屡屡受挫。理解VSCode作为轻量级编辑器的定位,以及MinGW-w64提供的gcc编译器在源码编译中的核心作用,是顺利完成环境配置的关键。环境变量的正确设置直接影响gcc命令能否全局调用,而C/C++插件则赋予编辑器语法高亮与智能提示能力。通过安装VSCode、配置MinGW-w64、安装插件、汉化界面并运行一个最简单的hello.c程序,就能系统掌握这套开源工具链的完整工作流。无论是用于课程学习、算法练习

weixin_42531923的博客 533

DMTF相关协议(一):Redfish和SMBIOS

Redfish 是一种管理标准,使用超媒体 RESTful 接口中的数据模型表示。该模型以标准的、机器可读的模式表示,消息的有效负载以 JSON 表示。该协议本身利用了 OData v4。由于它是一个超媒体 API,因此能够通过一致的接口表示各种实现。它具有管理数据中心资源、处理事件、长时间任务和发现的机制。

weixin_44032634的博客 2266

spring-aop浅析

Author ychhh_ Spring AOP介绍 基本概念 AOP 为Aspect Oriented Programming的缩写,意思为面向切面编程,是通过预编译方式和运行期间的动态代理实现程序功能的统一维护的技术,为Spring的核心技术之一 #mermaid-svg-zBSLmJNlQYW6Xra9 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-....

老6 645

26版SPSS操作教程(高级教程第十章)

#大道之行,在于坚持 #本期内容:二分类Logistic回归模型 #由于导师最近布置了学习SPSS这款软件的任务,因此想来平台和大家一起交流下学习经验,这期推送内容接上一次高级教程第九章的学习笔记,希望能得到一些指正和帮助~

你好! 1599

spring step 1 : 什么是spring

<br />学习一门技术之前还是花点时间来看看这门技术的特点,我们通过使用这种技术能够达到什么效果。<br /> <br />1.spring是什么?<br />2.spring能够干什么?<br />3.为什么使用spring?<br /> <br />1.spring是一个开源的框架,主要是由IoC,AOP(面向方面编程),抽象服务三部分组成。<br /> <br />2.spring的目标是要解决在企业级开发中复杂性而设计的,spring试图通过配置的方式来将开发过程中的紧耦合来解耦。

记录、分享 1347

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Sprint Boot项目搭建STEP6:Sprint Boot AOP静态代理Aspect

Sprint Boot项目搭建STEP6:Sprint Boot AOP静态代理Aspect1.pom引入spring-boot-starter-aop<依赖后编译。2.创建切面代码:前置增强@Before 1.pom引入spring-boot-starter-aop<依赖后编译。 <dependency> <groupId>org.springf...

weixin_43733834的博客 724

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Spring 全家桶学习——Step 1

Spring b站网课链接:https://www.bilibili.com/video/BV1Vf4y127N5?from=search&seid=4597070423034282547 课程介绍: Spring 概念 IOC容器 AOP JdbcTemplate 事务管理 Spring5新特性 Spring 概念 Spring是一个轻量级的开源的JavaEE框架 Spring可以解决企业运用开发的复杂性 两个核心部分:IOC AOP IOC:控制反转,把创建对象的过程交给Sprin

Wade__Hao的博客 375

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

上一篇: Java性能的优化
下一篇: Spring事务属性
java05
博客等级 码龄18年 21粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值