顾问包装通知

通知(advice)是Spring中的一种比较简单的切面,只能将切面织入到目标类的所有方法中,而无法对指定方法进行增强 顾问(advisor)是Spring提供的另外一种切面,可以织入到指定的方法中  接口 PointcutAdvisor

实现类:NameMatchMethodPointcutAdvisor(基于方法名称的增强顾问),RegexpMethodPointcutAdvice(基于正则表达式的增强顾问)

新增advisor包,实现顾问的测试用例

新建app-02.xml文件,内容如下

<!--将目标对象声明到Spring容器中-->
<bean id="doSomeService" class="com.cmy.service.impl.DoSomeServiceImpl"></bean>

<!--将advice声明到容器中-->
<bean id="advice" class="com.cmy.CodeAdvice.BeforeAndAfter"></bean>

<!--配置顾问:包装通知-->
<bean id="advisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
      <property name="advice" ref="advice"></property>
      <!--指定为say方法实现增强-->
      <property name="mappedName" value="say"></property>
</bean>

<!--配置代理工厂-->
<bean id="proxyfactory" class="org.springframework.aop.framework.ProxyFactoryBean">
       <property name="target" ref="doSomeService"></property>
       <!--将通知替换成为顾问-->
       <property name="interceptorNames" value="advisor"></property>
</bean>

以上文件使用的是NameMatchMethodPointcutAdvisor,当然也可替换成为 RegExpMethodPonitcutAdvisor,基于正则表达式通配方法名的顾问,可配置性更加优良。

<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
       <property name="advice" ref="advice"></property>
       <!--指定为带say的函数进行增强-->
       <property name="pattern" value=".*say.*"></property>
</bean>

顾问代理生成器

    顾问代理生成器,当我们声明好顾问后为目标对象生成代理对象。如果项目中 存在多个代理对象的话,需要实例化许多的ProxyFactoryBean,我们可以使用顾 问 代理生成器来解决这个问题。  

        顾问代理生成器主要分两种

      自动顾问代理生成器:DefaultAdvisorAutoProxyCreator

      名称顾问代理生成器:BeanNameAutoProxyCreator

  继续使用advisor包,创建app-03.xml文件,新增顾问代理生成器

--将目标对象声明到Spring容器中-->
<bean id="doSomeService" class="com.cmy.service.impl.DoSomeServiceImpl"></bean>
<!--将advice声明到容器中-->
<bean id="advice" class="com.cmy.CodeAdvice.BeforeAndAfter"></bean>
<!--顾问包装通知-->
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
       <property name="advice" ref="advice"></property>
       <!--指定为带say的函数进行增强-->
       <property name="pattern" value=".*say.*"></property>
</bean>

<!--名称顾问代理生成器:需要指定被代理的目标对象和顾问名-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
       <property name="beanNames" value="doSomeService"></property>
       <property name="interceptorNames" value="advisor"></property>
</bean>

创建测试用例

public class Demo2 {
    public static void main(String[] args) {
        //声明式增强 必须加载Spring容器
        ApplicationContext app = new ClassPathXmlApplicationContext("com/cmy/advisor/app-03.xml");
        //在Spring容器中已直接为DoSomeService创建好了代理对象 无需创建代理工厂
        DoSomeService doSomeService=(DoSomeService)app.getBean("doSomeService");
        doSomeService.say();
    }
}

IOC和DI的注解

      IOC:

                          @Component:实现Bean组件的定义

                          @Repository:用于标注DAO类,功能与@Component作用相当

                          @Service:用于标注业务类

                          @Controller:用于标注控制器

              DI:

                          @Resource(name="userService")

                               默认ByName方式,如果name确实默认按照ByType方式注入

                          @Autowired

                              默认ByType方式,如果出现同名类,则不能按照Type进行注入

                            需要使用@Qualifier 指明ID

使用注解方式实现Spring AOP   

实现AOP的注解有

@Aspect 声明切面

@Ponitcut 声明公共的切点表达式

@Before 前置增强

@AfterReturning 后置增强

@Around 环绕增强

@AfterThrowing 异常抛出增强

@After 最终增强

使用注解实现前置+后置增强

/**
 * 使用注解定义切面
 */
@Aspect
public class UserServiceLogger {
   @Pointcut("execution(* com.cmy.service.*.*(..))")
   public void pointcut() {}

   @Before("pointcut()")
   public void before(JoinPoint jp) {
      System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName()
            + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
   }
   @AfterReturning(pointcut = "pointcut()", returning = "returnValue")
   public void afterReturning(JoinPoint jp, Object returnValue) {
      System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName()
            + " 方法。方法返回值:" + returnValue);
   }
}

创建Spring的核心配置文件,开启Spring对IOC和AOP注解的支持

新增app-07.xml文件

<!--开启Spring IOC的注解支持 base-package 包扫描语句 com.cmy包下的注解-->
<context:component-scan base-package="com.cmy"/>
<!--配置增强类 交给Spring容器管理-->
<bean class="com.cmy.AfterAndBefore.UserServiceLogger"></bean>
<!--开启Spring AOP注解的支持-->
<aop:aspectj-autoproxy />

service包下给DoSomeServiceImpl声明@Service注解

Service("doSomeService")//与<bean id="doSomeService" class="XXX">相同
public class DoSomeServiceImpl implements DoSomeService {

    @Override
    public void say() {
        //int result=5/0;
        System.out.println("呵呵");
    }
}

测试类

public class Demo {
    public static void main(String[] args) {
        //声明式增强 必须加载Spring容器
        ApplicationContext app = new ClassPathXmlApplicationContext("com/cmy/AfterAndBefore/app-07.xml");
        //获取代理对象
        DoSomeService doSomeService=(DoSomeService)app.getBean("doSomeService");
        doSomeService.say();
    }
}
01-31 16:11