Spring笔记4
1. 不用Aop使用jdk的代理实现拦截,PersonServiceBean要求必须实现接口
接口
1 package cn.itcast.service; 2 3 public interface PersonService { 4 5 public abstract void save(); 6 7 }
被拦截的类
1 package cn.itcast.service.impl; 2 3 import cn.itcast.service.PersonService; 4 5 public class PersonServiceBean implements PersonService { 6 7 8 public String name; 9 10 public PersonServiceBean() { 11 } 12 13 public PersonServiceBean(String name) { 14 this.name = name; 15 } 16 17 public void save(){ 18 System.out.println("我是sava方法"); 19 } 20 21 public String getName() { 22 return name; 23 } 24 25 }
代理类
2. 如果类没有实现接口使用cglib实现 ,导入.../lib/cglib下的cglib-nodep-2.1_3.jar文件
代理类
1 package cn.itcast.aop; 2 3 import java.lang.reflect.Method; 4 5 import cn.itcast.service.impl.PersonServiceBean; 6 7 import net.sf.cglib.proxy.Enhancer; 8 import net.sf.cglib.proxy.MethodInterceptor; 9 import net.sf.cglib.proxy.MethodProxy; 10 11 public class CGlibFactory implements MethodInterceptor{ 12 public Object tagetObject; 13 14 public Object createProxyInstance(Object tagetObject){ 15 this.tagetObject = tagetObject; 16 Enhancer enhancer = new Enhancer(); 17 //指定父类,重写父类的所有非final方法 18 enhancer.setSuperclass(this.tagetObject.getClass()); 19 //指定回调函数,类实现MethodInterceptor接口 20 enhancer.setCallback(this); 21 return enhancer.create(); 22 } 23 24 @Override 25 public Object intercept(Object proxy, Method method, Object[] args, 26 MethodProxy methodProxy) throws Throwable { 27 PersonServiceBean bean = (PersonServiceBean)this.tagetObject; 28 Object result=null; 29 if(bean.getName()!=null){ 30 //将方法的调用委派给目标对象 31 result = methodProxy.invoke(tagetObject, args); 32 } 33 return null; 34 } 35 }
测试类
1 package cn.itcast.test; 2 3 import org.junit.Test; 4 5 import cn.itcast.aop.CGlibFactory; 6 import cn.itcast.aop.ProxyFactroy; 7 import cn.itcast.service.PersonService; 8 import cn.itcast.service.impl.PersonServiceBean; 9 10 public class AopTest { 11 @Test public void aopTest(){ 12 ProxyFactroy factory = new ProxyFactroy(); 13 //PersonService用接口类,传参的时候用非接口类,传名字的时候正常,不传名字的时候被拦截 14 PersonService service = (PersonService) factory.createProxyInstance(new PersonServiceBean("xxx")); 15 service.save(); 16 } 17 @Test public void aopTest2(){ 18 CGlibFactory factory = new CGlibFactory(); 19 //传名字的时候正常,不传名字的时候被拦截 20 PersonServiceBean service = (PersonServiceBean) factory.createProxyInstance(new PersonServiceBean("xxx")); 21 service.save(); 22 } 23 }
3. AOP的概念:
Aspect(切面):对横切性关注点的一个抽象,比如上面的Factory类
joinpoint(连接点):指被拦截到的点,在Spring中指方法,比如上面的save方法
Pointcut(切入点):是指我们要对哪些joinpoint进行拦截的定义
Advice(通知):指拦截到joinpoint之后要做的事情,通知分为前置通知,后置通知,例外通知,最终通知,环绕通知
Target(目标对象):代理的目标对象
Weave(织入):将Aspect应用到target对象并导致Proxy对象创建的过程
Introduction(引入):在不修改代码的前提下,Introduction可以为类动态的添加一些方法或Field
4. 使用Spring的aop实现切面编程:
1)引入aop的jar包
2)加入命名空间,第5,10行,第11行打开aop注解
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:aop="http://www.springframework.org/schema/aop" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-2.5.xsd 10 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd "> 11 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 12 </beans>
3)创建要拦截的bean以及接口
1 package cn.itcast.service; 2 3 4 import java.util.List; 5 import java.util.Map; 6 import java.util.Properties; 7 import java.util.Set; 8 9 public interface PersonService { 10 11 public abstract void save(); 12 public abstract void update(); 13 public abstract String getPeresonName(); 14 }
1 package cn.itcast.service.imp; 2 3 import cn.itcast.service.PersonService; 4 5 public class PersonServiceBean implements PersonService { 6 7 @Override 8 public String getPeresonName() { 9 return "xxx"; 10 11 } 12 13 @Override 14 public void update() { 15 System.out.println("update"); 16 17 } 18 19 @Override 20 public void save() { 21 System.out.println("save"); 22 23 } 24 25 }
4)创建切面,切入点,以及前置通知
1 package cn.itcast.service; 2 3 import org.aspectj.lang.annotation.Aspect; 4 import org.aspectj.lang.annotation.Before; 5 import org.aspectj.lang.annotation.Pointcut; 6 7 @Aspect//切面 8 public class Interceptor { 9 //切入点,(返回值,然后是包名,类名,方法,参数)*代表任意,..代表所有 10 @Pointcut("execution(* cn.itcast.service.imp.PersonServiceBean.*(..))") 11 private void anyWethod(){}//声明一个切入点 12 13 //前置通知,参数为切入点 14 @Before("anyWethod()") 15 public void doAcessCheak(){ 16 System.out.println("前置通知"); 17 } 18 19 }
5)将切面以及bean交给Spring管理
1 <bean id="myInterceptor" class="cn.itcast.service.Interceptor"></bean> 2 <bean id="personService" class="cn.itcast.service.imp.PersonServiceBean"></bean>
6)测试
ApplicationContext ctr = new ClassPathXmlApplicationContext("beans.xml"); PersonService personService = (PersonService) ctr.getBean("personService"); personService.save();
控制台会输出前置通知的内容,然后输出save方法中的内容
5. 前置通知
1 @Before("anyWethod()") 2 public void doAcessCheck(){ 3 System.out.println("前置通知"); 4 }
@Before("anyWethod() && args(name)")//表示拦截参数为一个且是String类型的方法 public void doAcessCheck(String name){ System.out.println("前置通知"+name); }
6. 后置通知
1 @AfterReturning("anyWethod()") 2 public void doAccessCheckAfter(){ 3 System.out.println("后置通知"); 4 }
1 @AfterReturning(pointcut="anyWethod()" ,returning="result" )//表示拦截返回值为String类型的方法 2 public void doAccessCheckAfter(String result){ 3 System.out.println("后置通知"+result); 4 }
7. 最终通知
1 @After("anyWethod()") 2 public void doAfter(){ 3 System.out.println("最终通知"); 4 }
8 例外通知
1 @AfterThrowing("anyWethod()") 2 public void dofterThrowing(){ 3 System.out.println("例外通知"); 4 }
1 @AfterThrowing(pointcut="anyWethod()",throwing="e")//表示拦截参数为Exception的异常 2 public void dofterThrowing(Exception e){ 3 System.out.println("例外通知"+e); 4 }
9. 环绕通知
1 @Around("anyWethod()") 2 public Object doAround(ProceedingJoinPoint pjp) throws Throwable{ 3 System.out.println("进入方法"); 4 Object result = pjp.proceed(); 5 System.out.println("退出方法"); 6 return result; 7 }
10. 用xml方式实现,不使用注解
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:aop="http://www.springframework.org/schema/aop" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-2.5.xsd 10 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd "> 11 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 12 <bean id="personService" class="cn.itcast.service.imp.PersonServiceBean"></bean> 13 <bean id="sapectBean" class="cn.itcast.service.Interceptor"></bean> 14 <aop:config> 15 <aop:aspect id="asp" ref="sapectBean"> 16 <aop:pointcut id="aspCut" expression="execution(* cn.itcast.service.imp.PersonServiceBean.*(..))"/> 17 <aop:before pointcut-ref="aspCut" method="doAcessCheck"/> 18 <aop:after-returning pointcut-ref="aspCut" method="doAccessCheckAfter"/> 19 <aop:after-throwing pointcut-ref="aspCut" method="dofterThrowing"/> 20 <aop:after pointcut-ref="aspCut" method="doAfter"/> 21 <aop:around pointcut-ref="aspCut" method="doAround"/> 22 </aop:aspect> 23 </aop:config> 24 </beans>
aop
我要青春像陈孝正一样,不能有一毫米的误差!
我要青春像合伙人一样,为了自尊而战!