顾问包装通知
通知(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();
}
}