Spring学习笔记专题二

专题二

(1)注解

1,注解的作用:给Java结构添加标记;

2,注解的使用:使用注解一般需要三方面参与:

1,注解类;

2,需要标记的目标类型;

3,用于处理目标类型的处理程序;

3,Retention:把注解保留的时机

1,SOURCE:保留在源代码级别,一般供编辑器级别使用

2,CLASS:保留到字节码级别,一般用编译器使用

3,RUNTIME:保留到运行时,一般供需要其他程序解析的情况使用;

4,Target:注解能够写在什么位置:

1,TYPE:类,接口等类型;

2,METHOD:方法;

3,CONSTRUCTOR:构造方法;

4,FIELD:字段;

5,注解的使用实例:

1,把注解作为标记,配合isAnnoataion方法使用;

2,注解携带信息:

1,注解中属性的添加方式;

2,注解中属性的默认值;

3,getAnnotation方法的使用;

(2)IoC的注解支持

不需要在配置文件中配置bean

1,首先,Spring针对IoC的注解支持,是不支持factory-bean和factory-method;用FactoryBean;

2,使用方式:

先在SomeBean中配置注解@Component(“somebean”)


配置文件


使用分析,Spring到底是怎么处理的?

Spring在内部提供了一个类专门用于处理打了标签的Bean,这个类就是通过context:component-scan这个标签引入的。

注解还需加入context:annotation-config

这个元素,只是在Spring3.X之后,这个元素被ApplicationContext自动引入进来。但是,在Web环境下必须要手动引入该元素。原因:在Web环境下使用的ApplicationContext和使用SpringJUnit创建的ApplicationContext是不一样的。

3,Spring中提供的其他IoC标签

1,版型标签:就是代表不同的样子;四种标签也能起到和component相同的作用

1,@Controller:用于控制器(Action/如果在SpringMVC中,@Controller有特殊意义);

2,@Service:用于服务对象;

3,@Repository:用于DAO;

4,@Component:用于其他组件;

注意,不同版型标签达到的目的都是一样的,都是让spring去扫描这些类;这些标签对于Spring没有区别,是写给程序猿看的;

2,@Scope标签:


3,init-method和destory-method


(3)DI相关的注解:

1,在Spring中,有两个注解可以用来做DI:@Autowired,  @Resource

2,@Autowired

1,@Autowired标签可以加在字段或者setter方法上,如果加在setter方法上,通过setter方法注入,如果加在字段上,直接通过字段设置值(可以省略setter方法);

2,@Autowired执行流程:

1,spring加载配置文件,解析所有的bean;

2,使用spring的@Autowired标签解析器解析每一个bean;

3,如果在字段或者方法上面发现了@Autowired标签,

1,找到对应的对象;

2,通过setter或者field注入值;

3,@Autowired标签寻找对象的方法:

1,默认通过类型寻找对象;factory.getBean(class);

2,如果找到多个该类型的实例,再按照属性或者字段的名称匹配;

3,如果1,2都匹配不到,报错;

4,默认如果没有找到任何该类型的bean,报错(相当于默认@Required);

5,可以通过设置@Autowired标签的required属性来设置是否必须要求有对象;

6,可以配合@  Qualifier标签来限定注入bean的名称;

4,@Autowired标签高级用法:

1,可以注入Spring中的关键对象,比如BeanFactory,ApplicationContext等;

5,重新思考测试:

1,在Spring的测试中,不应该注入容器,再从容器中拿要测试的对象,而应该直接注入要测试的对象;

2,Spring的测试就是按照使用测试对象的方式来测试测试对象;


3,@Resource

1,@Resource标签是JAVAEE的标准标签;也可以完成DI;

2,@Resource标签也可以加在setter或者字段上;

3,@Resource标签寻找对象的方式:

1,首先按照属性或者字段的名字寻找;

2,如果找不到,再按照类型寻找;

3,如果1,2都找不到,报错;

4,@Resource标签必须注入;

5,可以使用@Required的name属性指定bean,但是如果指定了name属性,就不能按照type寻找了;

(可以看出@Autowired和@Resource寻找对象的方式区别是,前者先按照类型寻找对象,然后再按照属性或字段名称匹配;后者是先按照属性或者字段的名字寻找,后按照类型寻找。)

4,选择?XML还是Annotation:

1,XML配置稍微复杂,Annotation相对简单;

2,XML配置能实现代码和配置的分离,Annotation做不到;

3,第三方的无法使用Annotation;

选择?一般情况下,会使用XML+Annotation的方式(第三方的类都使用XML,自己的代码使用Annotation);

4,选择?XML还是Annotation:

1,XML配置稍微复杂,Annotation相对简单;

2,XML配置能实现代码和配置的分离,Annotation做不到;

3,第三方的无法使用Annotation;

选择?一般情况下,会使用XML+Annotation的方式(第三方的类都使用XML,自己的代码使用Annotation);

(4)在service上面开启事务造成了什么问题?

1,代码污染的问题;(本来只应该出现在dao中session跑到service上了);

2,责任不分离;(service的方法本来只应该关心业务,现在开事务也是service管了);

3,大量重复的代码;(try..catch..finally);


解决第一个问题:责任分离的问题:

1,目前的方式:


2,有中介的结构


房屋中介解决了责任分离的问题;这个模式在Java中就是装饰模式;


装饰模式的问题:

1,只能解决责任分离的问题;代码污染和代码重复都没法解决;

2,需要为每一个目标对象创建一个装饰对象;

3,使用装饰模式,客户端是知道目标对象,是不安全的;

3,房屋代理模式


两个问题:

1,静态代理模式和装饰模式区别太小,装饰模式使用构造器设置真实对象,而静态代理模式使用setter设置真实对象;除此之外,没有感觉到什么区别?

装饰模式强调的是对原对象的功能的增强;强调的是装饰这个过程

静态代理模式强调的是对原对象的功能增强之后的结果


2,注意,静态代理模式在配置的时候需要把真实的对象隐藏起来;


静态代理模式的问题:

1,只能解决责任分离的问题;代码污染和代码重复都没法解决;

2,需要为每一个目标对象创建一个代理对象;

(5)JDK中的动态代理

测试代码:


JDK动态代理的拦截器类:


小结:

1,InvcationHander的三个参数:

1,Proxy:代表代理之后的对象;

2,method:代表当前正在执行的方法;

3,args:代表当前执行方法的参数;

2,Proxy:Proxy代表一个代理对象,在这个对象上面有个静态的工厂方法用于生产动态代理对象:

Proxy.newProxyInstance方法的参数:

1,ClassLoader:目标对象的类加载器;

2,Class[]:要代理的接口;

3,InovcationHandler:本次代理的拦截器;

3,画图理解InvocationHandler的执行流程;

5,注意:

1,JDK动态代理的要求被代理的对象必须有接口;

2,最小代理单位是类;如果要区分一个类中的方法,自己在逻辑中根据方法名区别;


问题:

1,如果一个类没有实现接口怎么办?

2,还要为每一个类配置一个代理对象?

如果一个类没有实现接口怎么办?

就只能使用继承的方式来实现动态代理;

比较流行的两个用于继承的方式实现动态代理的工具:

javassist:hibernate推荐使用的使用继承完成动态代理的工具;

cglib:spring默认使用的

结论:

使用动态代理,

如果代理的目标对象是有接口的对象,我们就可以使用Proxy来实现动态代理;

如果代理的目标对象没有实现接口,就可以使用cglib来实现动态代理;

这个结论就是Spring中AOP的基本原理!!!!

(6)AOP

1、什么是AOP?

AOP:Aspectoritention programming(面向切面编程)

2、什么是切面?


3、AOP的目的:

AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,

便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

4、AOP的优势:

降低模块的耦合度、使系统容易扩展、更好的代码复用性

5、Spring的AOP使用动态代理实现:如果一个类实现了接口,那么spring就使用JDK的动态代理完成AOP;

如果一个类没有实现接口,那么spring就是用cglib完成AOP;

6、AOP当中的概念:

1.切入点(Pointcut):在哪些类,哪些方法上切入(where);

2.增强(Advice):早期翻译为通知,在方法执行的什么时机(when:方法前/方法后/方法前后)做什么(what:增强的功能);

3.切面(Aspect):切面=切入点+通知,通俗点就是:什么时机,什么地点,做什么!

4.织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)。

(7)Spring中使用AOP(XML,Annotation):

1、AOP最重要的一点,就是想找一个方法来统一描述切入点;

因为Java是面向对象的,所以在Java中,是没有办法使用Java提供的语言来描述切入点;

2、因为AOP编程是实际开发当中比较重要的一种开发思想,所以,很多公司联合起来,组成了一个叫做AOP联盟的组织,这个组织提供了一套标准的用于描述切入点的语法;创建了一个Java的扩展程序:AspectJ;

3、AOP定义的切入点语法:

execution(modifiers-pattern?ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?)

public abstract voidcom._520it.spring._7_jdkproxy.IEmployeeService.save(com._520it.spring._7_jdkproxy.Employee)throws Exception

示例:

任意公共方法的执行:

execution(public* *(..))

任何一个名字以“set”开始的方法的执行:

execution(* set*(..))

AccountService接口定义的任意方法的执行:

execution(* com.xyz.service.AccountService.*(..))

在service包中定义的任意方法的执行:

execution(* com.xyz.service.*.*(..))

在service包或其子包中定义的任意方法的执行:

execution(*com.xyz.service..*.*(..))

(8)Spring中使用XML来配置AOP:

1,写一个类,来提供做什么;

2,在Spring中配置目标对象;

3,导入相关的包(spring-aop.jar,  aopalliance.jar,  aspectj-wever)

4,在spring配置文件中,配置aop:


5,测试代码:


6,问题:执行流程:

1,Spring先扫描AOP配置;

2,找到aop中配置的定义的所有的增强;(切入点表达式,做什么的类,做什么的方法)

3,扫描所有的普通bean:

1,实例化这些bean--->instance;

2,得到这些bean的类型,并且,用所有的切入点表达式的方法之前的模式去匹配这个bean的类型;

1,如果匹配不上(说明这个类型是不需要AOP增强的)

2,如果能够匹配;

1,根据类是否有接口来选择动态代理的方式;如果有接口使用JDK,如果没有接口使用cglib;

2,创建invocationHandler,需要知道要在invoke方法中做些什么事情?

1,如果配置的是aop:before,其实就是在invoke方法执行之前调用txManager.beginTransaction;

2,如果配置的是aop:after-returning,其实就是在invoke正常执行之后调用txManager.commit;

3,如果....

3,使用这个invocationHandler+实际的目标对象(instance),通过动态代理创建出一个代理对象(proxy);

4,用配置的bean的id+proxy保存到spring容器中;

4,从容器中拿IEmployeeService的时候,得到的直接就是代理之后的proxy对象;

(9)各种不同的增强:aop:before(前置增强):在方法执行之前执行增强;

aop:after-returning(后置增强):在方法正常执行完成之后执行增强;

aop:throwing(异常增强):在方法抛出异常退出时执行增强;

aop:after(最终增强):在方法执行之后执行,相当于在finally里面执行;可以通过配置throwing来获得拦截到的异常信息

aop:around(环绕增强):最强大的一种增强类型。环绕增强可以在方法调用前后完成自定义的行为,环绕通知有两个要求,

1,方法必须要返回一个Object(返回的结果)

2,方法的第一个参数必须是ProceedingJoinPoint(可以继续向下传递的切入点)

JoinPoint获取方法相关内容

publicvoid beginTransaction(JoinPoint jp) {

System.out.println("开启事务.....");

System.out.println(jp.getSignature());//方法签名

System.out.println(jp.getTarget());//真实主题对象

System.out.println(jp.getArgs());//方法参数

}


posted @ 2017-02-27 09:26  Andya_net  阅读(11)  评论(0编辑  收藏  举报  来源