(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());//方法参数
}