顾问包装通知
通知(advice)是Spring中的一种比较简单的切面,只能将切面织入到目标类的所有方法中,而无法对指定方法进行增强
顾问(advisor)是Spring提供的另外一种切面,可以织入到指定的方法中
实现类:NameMatchMethodPointcutAdvisor(基于方法名称的增强顾问),RegexpMethodPointcutAdvice(基于正则表达式的增强顾问)
实例
接口
package com.spring.advisor; /*业务接口*/ public interface IService { //业务方法 public void doSome(); public void say(); }
实现类
/*业务类*/ public class IServiceImpl implements IService{ @Override public void doSome() { System.out.println("====真实业务==="); } @Override public void say() { System.out.println("====say====="); } }
增强类
/*增强类*/ public class MyAdvisor implements MethodBeforeAdvice, AfterReturningAdvice { @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("===后置增强===="); } @Override public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("====前置增强===="); } }
配置
NameMatchMethodPointcutAdvisor(基于方法名称的增强顾问)
<!--注入业务Bean--> <bean id="iServiceImpl" class="com.spring.advisor.IServiceImpl"></bean> <!--切面/通知--> <bean id="testBean" class="com.spring.advisor.TestBean"></bean> <bean id="myAdvisor" class="com.spring.advisor.MyAdvisor"></bean> <!--顾问包装通知--> <bean id="advisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice" ref="myAdvisor"></property> <property name="mappedNames" value="*a*"></property> </bean> <bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="iServiceImpl"></property> <property name="interceptorNames" value="advisor"></property> </bean>
RegexpMethodPointcutAdvice(基于正则表达式的增强顾问)
<!--注入业务Bean--> <bean id="iServiceImpl" class="com.spring.advisor.IServiceImpl"></bean> <!--切面/通知--> <bean id="testBean" class="com.spring.advisor.TestBean"></bean> <bean id="myAdvisor" class="com.spring.advisor.MyAdvisor"></bean> <!--顾问包装通知--> <bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="myAdvisor"></property> <!--.代表单个字符 *代表一项出现0-n次 +代表前一项出现1-n次 至少包含两个字符--> <property name="patterns"> <list> <value>.*do.*</value> </list> </property> </bean> <bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="iServiceImpl"></property> <property name="interceptorNames" value="advisor"></property> </bean>
测试类
public class AdvisorTest { @Test public void advisorTest() { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取代理工厂Bean IService idoSomeServiceProxy = (IService) ctx.getBean("iServiceImpl"); idoSomeServiceProxy.doSome(); idoSomeServiceProxy.say(); } }
顾问代理生成器
顾问代理生成器,当我们声明好顾问后为目标对象生成代理对象。如果项目中 存在多个代理对象的话,需要实例化许多的ProxyFactoryBean,我们可以使用顾 问 代理生成器来解决这个问题。
顾问代理生成器主要分两种
- 自动顾问代理生成器:DefaultAdvisorAutoProxyCreator
- 名称顾问代理生成器:BeanNameAutoProxyCreator
实例
接口
/*业务接口*/ public interface IService { //业务方法 public void doSome(); public void say(); }
实现类
/*业务类*/ public class IServiceImpl implements IService{ @Override public void doSome() { System.out.println("====真实业务==="); } @Override public void say() { System.out.println("====say====="); } }
增强类
/*增强类*/ public class MyAdvisor implements MethodBeforeAdvice, AfterReturningAdvice { @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("===后置增强===="); } @Override public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("====前置增强===="); } }
配置
- 自动顾问代理生成器:DefaultAdvisorAutoProxyCreator
<!--注入业务Bean--> <bean id="iServiceImpl" class="com.spring.advisor.IServiceImpl"></bean> <!--切面/通知--> <bean id="testBean" class="com.spring.advisor.TestBean"></bean> <bean id="myAdvisor" class="com.spring.advisor.MyAdvisor"></bean> <!--顾问包装通知--> <!--<bean id="advisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice" ref="myAdvisor"></property> <property name="mappedNames" value="*a*"></property> </bean>--> <!--顾问包装通知--> <bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="myAdvisor"></property> <!--.代表单个字符 *代表一项出现0-n次 +代表前一项出现1-n次 至少包含两个字符--> <property name="patterns"> <list> <value>.*do.*</value> </list> </property> </bean> <!--默认顾问自动代理生成器--> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
- 名称顾问代理生成器:BeanNameAutoProxyCreator
<!--注入业务Bean--> <bean id="iServiceImpl" class="com.spring.advisor.IServiceImpl"></bean> <!--切面/通知--> <bean id="testBean" class="com.spring.advisor.TestBean"></bean> <bean id="myAdvisor" class="com.spring.advisor.MyAdvisor"></bean> <!--顾问包装通知--> <!--<bean id="advisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice" ref="myAdvisor"></property> <property name="mappedNames" value="*a*"></property> </bean>--> <!--顾问包装通知--> <bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="myAdvisor"></property> <!--.代表单个字符 *代表一项出现0-n次 +代表前一项出现1-n次 至少包含两个字符--> <property name="patterns"> <list> <value>.*do.*</value> </list> </property> </bean> <!--BeanName自动代理生成器--> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <!--配置BeanName--> <property name="beanNames" value="iServiceImpl,testBean"></property> <!--拦截顾问--> <property name="interceptorNames" value="advisor"></property> </bean>
IOC注解
配置
<context:component-scan base-package="com.spring"/>
实体类
public class UserInfo implements Serializable { private Integer user_id; private String user_name; public Integer getUser_id() { return user_id; } public void setUser_id(Integer user_id) { this.user_id = user_id; } public String getUser_name() { return user_name; } public void setUser_name(String user_name) { this.user_name = user_name; } }
Dao层接口
/** * Dao层接口 */ public interface IUserInfoMapper { public int addUser(UserInfo info); }
实现类
/** * Dao层标识 @Repository */ @Repository public class IUserInfoMapperImpl implements IUserInfoMapper{ @Override public int addUser(UserInfo info) { System.out.println("添加成功"); return 1; } }
测试类
public class iocTest { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext1.xml"); IUserInfoService bean=(IUserInfoService)context.getBean("iUserInfoServiceImpl"); bean.addUser(new UserInfo()); } }
输出
注释
/*业务类*/ @Service("IdoSomeService") public class IdoSomeService { public void doSome(){ System.out.println("业务类当中的doSome方法"); } public void say(){ System.out.println("业务类当中的say方法"); } }
@Pointcut("execution(* *..aop.*.do*(..))") public void pointCut(){ } @Before("pointCut()") public void before(){ System.out.println("==========前置增强=========="); } @AfterReturning("pointCut()") public void after(){ System.out.println("========后置增强========="); } }
测试类
public class aopTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml"); IdoSomeService bean = (IdoSomeService) context.getBean("IdoSomeService"); bean.doSome(); bean.say(); } }
输出
使用注解方式实现Spring AOP
- 实现AOP的注解有
- @Aspect 声明切面
- @Ponitcut 声明公共的切点表达式
- @Before 前置增强
- @AfterReturning 后置增强
- @Around 环绕增强
- @AfterThrowing 异常抛出增强
- @After 最终增强
/*业务类*/ @Service("IdoSomeService") public class IdoSomeService { public void doSome(){ System.out.println("业务类当中的doSome方法"); } public void say(){ System.out.println("业务类当中的say方法"); } }
增强类
/*增强类*/ @Aspect @Component public class MyAdvice { @Pointcut("execution(* *..aop.*.do*(..))") public void pointCut() { } @Before("pointCut()") public void before() { System.out.println("==========前置增强=========="); } @AfterReturning("pointCut()") public void after() { System.out.println("========后置增强========="); } @After("pointCut()") public void doAfter() { System.out.println("======最终增强======="); } /*@AfterThrowing("pointCut()") public void doAfterThrowing() { System.out.println("======异常抛出增强======="); }*/ @Around("pointCut()") public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { /** * 环绕通知内部一定要确保执行该方法,如果不执行该方法,业务bean中被拦截的方法就不会被执行。 * 当执行该方法,如果后面还有切面的话,它的执行顺序应该是这样的:先执行后面的切面,如果后面没有切面了, * 再执行最终的目标对象的业务方法。若不执行该方法,则后面的切面,业务bean的方法都不会被执行。 */ // if () { // 判断用户是否有权限, System.out.println("进入方法"); Object result = pjp.proceed(); System.out.println("退出方法"); // } return result; } }
@Pointcut("execution(* *..aop.*.do*(..))")
public void pointCut() {
}
@Before("pointCut()")
public void before() {
System.out.println("==========前置增强==========");
}
@AfterReturning("pointCut()")
public void after() {
System.out.println("========后置增强=========");
}
@After("pointCut()")
public void doAfter() {
System.out.println("======最终增强=======");
}
/*@AfterThrowing("pointCut()")
public void doAfterThrowing() {
System.out.println("======异常抛出增强=======");
}*/
@Around("pointCut()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
/**
* 环绕通知内部一定要确保执行该方法,如果不执行该方法,业务bean中被拦截的方法就不会被执行。
* 当执行该方法,如果后面还有切面的话,它的执行顺序应该是这样的:先执行后面的切面,如果后面没有切面了,
* 再执行最终的目标对象的业务方法。若不执行该方法,则后面的切面,业务bean的方法都不会被执行。
*/
// if () { // 判断用户是否有权限,
System.out.println("进入方法");
Object result = pjp.proceed();
System.out.println("退出方法");
// }
return result;
}
测试类
public class aopTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml"); IdoSomeService bean = (IdoSomeService) context.getBean("IdoSomeService"); bean.doSome(); bean.say(); } }