spring的bean管理(注解)
注解介绍
1 代码里面特殊标记,使用注解可以完成功能
2 注解写法@注解名称(属性名称=属性值)
3 注解使用在类上面,方法上面 和 属性上面
自动装配Bean
spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系。因此,如果可能的话,可以自动让Spring通过检查BeanFactory中的内容,来替我们指定bean的协作者(其他被依赖的bean)。
简而言之,就是对于bean当中引用的其他bean时不需要我们自己去配置它该使用哪个类,Spring 的自动装配可以帮助我们完成这些工作。
autowire 的值有5个:default, no, byName, byType, constructor。其中default等价于no
自动装配优点:
l 自动装配能显著减少配置的数量。
l 自动装配可以使配置与Java代码同步更新。
在开发过程中推荐采用自动装配,而在系统趋于稳定的时候改为显式装配的方式。
自动装配有5中类型:
byName
根据属性名自动装配。此选项将检查容器并根据id的名字查找与属性名完全一致的bean,并将其与属性自动装配
byType
如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配;
如果没有找到相匹配的bean,则什么事都不发生,属性也不会被设置
constructor
与byType的方式类似,不同之处在于它应用于构造器参数。
如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
autodetect
通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。高版本已经弃用no
默认 。 必须显示的使用"<ref />"标签明确地指定bean合作者,对于部署给予更大的控制和明了
spring注解开发准备
1 导入jar包(可通过maven管理)
(1)导入基本的jar包
(2)导入aop的jar包
2 创建类,创建方法
3 创建spring配置文件,引入约束
(1)第一篇做ioc基本功能,引入约束beans
(2)做spring的ioc注解开发,引入新的约束
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">4 开启注解扫描
<!--第一步 开启注解扫描--> <context:annotation-config /> <!--第二步 设置需要扫描的包--> <context:component-scan base-package="com.keduox1"/>
注解创建对象
1.在创建对象上面使用注解@Repository(value = "userDao") public class UserDao { public void add(){ System.err.println("成功使用了user对象"); } }2.创建对象有四个注解(1)@Component
(2)@Controller
(3)@Service
(4)@Repository
目前这四个注解功能是一样的,都创建对象。只是针对于java三层模式,便于理解。
3.创建对象是单实例还是多实例@Component(value = "user") /*@Scope(value = "prototype")每一次都会创建一个新的对象*/ @Scope(value = "prototype") public class User implements Serializable {
注解注入属性
@Component(value = "userservice") public class UserService { //@Autowired是根据类型注入数据,与@Repository的value的值无关 // @Autowired //根据名称(id)注入数据 //如果@Repository没有value值, //那么@Resource自动指定的值是UserDao的类名的首字母小写的值 @Resource(name="userDao") private UserDao userDao; }
配置文件和注解混合使用
Bean的生命周期1 创建对象操作使用配置文件方式实现
2 注入属性的操作使用注解方式实现
<!-- 开启注解扫描 (1)到包里面扫描类、方法、属性上面是否有注解 --> <context:component-scan base-package="cn.itcast"></context:component-scan> <!-- 配置对象 --> <bean id="bookService" class="cn.itcast.xmlanno.BookService"></bean> <bean id="bookDao" class="cn.itcast.xmlanno.BookDao"></bean> <bean id="ordersDao" class="cn.itcast.xmlanno.OrdersDao"></bean>
spring Framework支持五种作用域(其中有三种只能用在基于web的Spring ApplicationContext)。内置支持的作用域分列如下:
singleton
在每个Spring IoC容器中一个bean定义对应一个对象实例。
prototype
一个bean定义对应多个对象实例。
request(了解)
在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用域仅在基于web的Spring 开发情形下有效。
session(了解)
在一个HTTP Session 中,一个bean定义对应一个实例。该作用域仅在基于web的Spring开发情形下有效。
global session(了解)
在一个全局的HTTP Session 中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext 情形下有效。
生命周期: 构造器、init方法、获取bean后的操作、destroy方法(ctx.close时执行).
注意:如果bean的scope设为prototype时,当ctx.close时,destroy方法不会被调用.
原因:对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法。但对prototype而言,任何配置好的析构生命周期回调方法都将不会 被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被prototype作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。)谈及prototype作用域的bean时,在某些方面你可以将Spring容器的角色看作是Java new 操作的替代者。任何迟于该时间点的生命周期事宜都得交由客户端来处理。
1. 生命周期图
2. 生命周期顺序(一).Bean的建立
由BeanFactory读取Bean定义文件,并生成各个实例
(二).属性注入
执行相关的Bean属性依赖注入
(三).BeanNameAware的setBeanName()
如果Bean实现BeanNameAwar接口,则执行setBeanName()
(四).BeanFactoryAware的setBeanFactory()
如果Bean实现BeanFactoryAware接口,则执行setBeanFactory()
(五).ApplicationContextAware接口
setApplicationContext()方法
(六).BeanPostProcessors的processBeforeInitialization()
如果有任何BeanPostProcessors实例与Bean实例关联,则执行BeanPostProcessors实例processBeforeInitialization()
(七).InitializingBean的afterPropertiesSet()
如果Bean有实现InitializingBean,则执行afterPropertiesSet()
(八).Bean定义文件中定义init-method
<bean id="…" class="…" init-method="initBean">
(九).BeanPostProcessors的processaAfterInitialization()
如果有任何的BeanPostProcessors实例与Bean实例关联,则执行BeanPostProcessors实例的processaAfterInitialization()
(十).DisposableBean的destroy()
在容器关闭时,如果Bean类实现DisposableBean接口,则执行destroy()
(十一).Bean定义文件中定义destroy-method
<bean id="…" class="…"destroy-method="destroyBean">
3.各种接口方法分类
Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
1、Bean自身的方法 : 这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法
2、Bean级生命周期接口方法 : 这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法
3、容器级生命周期接口方法 : 这个包括了InstantiationAwareBeanPostProcessor和 BeanPostProcessor这两个接口实现,一般称它们的实现类为“后处理器”。
4、工厂后处理器接口方法 : 这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器 接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
详细生命周期:http://www.cnblogs.com/zrtqsk/p/3735273.html
Aop面向切面编程
1 aop:面向切面(方面)编程,扩展功能不修改源代码实现
2 AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
3 aop底层使用动态代理实现
(1)第一种情况,有接口情况,使用动态代理创建接口实现类代理对象
(2)第二种情况,没有接口情况,使用动态代理创建类的子类代理对象
aop核心概念
软件系统,可看作由一组关注点组成。其中,直接的业务关注点,是核心关注点。而为核心关注点提供服务的,就是横切关注点。而封装各种横切关注点的类,就是切面。
横切关注点与切面之间:横切关注点是切面中封装的各种方法。即横切关注点是各种服务性方法,切面是封装各种横切关注点的类。就是类与方法的关系。
备注:业务处理的主要流程是核心关注点,扩展(增强)核心关注点的部分是横切关注点
1、横切关注点
软件系统,可看作由一组关注点组成。其中,直接的业务关注点,是核心关注点。而为核心关注点提供服务的,就是横切关注点。一般情况下,切面中封装的方法都是横切关注点。
2、切面(aspect)
封装各种横切关注点的类,就是切面。
3、连接点(joinpoint)
所谓连接点是指那些被拦截到的点。就是spring配置文件中的切入点表达式中需要拦截的所有的方法。
4、切入点(pointcut)
所谓切入点是指我们要对那些joinpoint进行拦截的定义。
在类里面可以有很多方法被增强,比如实际操作中,需要增强类里面的add方法和update方法,那么当前被增强的方法称为切入点。
5、通知(advice)
所谓通知是指拦截到joinpoint之后所要做的事情(增强的代码)就是通知。通知分为前置通知、后置通知、异常通知、最终通知、环绕通知。
前置通知:在方法执行前执行
后置通知:在方法执行后执行
异常通知:在执行核心关注点过程中,如果抛出异常则会执行
返回通知:在后置之前执行(如果出现异常,不执行)--在方法正常执行通过之后执行的通知
环绕通知:在方法之前和之后执行
6、目标对象(Target)
代理的目标对象,即增强方法所在的类。
7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程
或者说把增强用到类的过程
8、引入(introduction)
一般不适用
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
Spring的aop操作
1 在spring里面进行aop操作,使用aspectj实现
(1)aspectj不是spring一部分,和spring一起使用进行aop操作
(2)Spring2.0以后新增了对AspectJ支持
2 使用aspectj实现aop有两种方式
(1)基于aspectj的xml配置
(2)基于aspectj的注解方式
aop编程准备
1 除了导入基本的jar包之外,还需要导入aop相关的jar包
![]()
2 创建spring核心配置文件,导入aop的约束
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">3.使用表达式配置切入点
常用表达式:
下面方法中的..表示:可以包含参数
execution(* com.yunlian.service.UserService.add(..))
execution(* com.yunlian.service.UserService.*(..))—某个类的所有方法
execution(* com.yunlian.service.*.*(..))---service包下面的所有类的所有方法
execution(* *.*(..))---所有类中的所有方法
注解方式实现
第一步:创建需要增强的类
public class Book { public void add() { System.out.println("add..........."); } }第二步:创建增强的类
/** * aop切面编程。 增强Book类 */ public class MyBook { public void before1() { System.out.println("前置增强......"); } public void after1() { System.out.println("后置增强......"); } //环绕通知 public void around1(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { //方法之前 System.out.println("方法之前....."); //执行被增强的方法 proceedingJoinPoint.proceed(); //方法之后 System.out.println("方法之后....."); } }第三步:配置文件
<!-- 1 配置对象 --> <bean id="book" class="cn.itcast.aop.Book"></bean> <bean id="myBook" class="cn.itcast.aop.MyBook"></bean> <!-- 2 配置aop操作 --> <aop:config> <!-- 2.1 配置切入点 连接点 --> <aop:pointcut expression="execution(* cn.itcast.aop.Book.*(..))" id="pointcut1"/> <!-- 2.2 配置切面 把增强用到方法上面--> <aop:aspect ref="myBook"> <!-- 配置增强类型 method: 增强类里面使用哪个方法作为前置 --> <aop:before method="before1" pointcut-ref="pointcut1"/> <aop:after-returning method="after1" pointcut-ref="pointcut1"/> <aop:around method="around1" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config>