<bean id="personService" class="com.jary.service.impl.PersonServiceBean"/>
通过scope来设置作用域范围
默认作用域:
singleton(
每次从spring容器中取出同一个对象)
<bean id="personService" class="com.jary.service.impl.PersonServiceBean
" scope="singleton"/>
singleton作用域:当spring ioc容器中一个bean只有一个实例对象,默认情况下初始化容器时,就初始化bean
但是我们可以指定bean节点的lazy-init=ture来延时初始化bean
<bean id="personService" class="com.jary.service.impl.PersonServiceBean
" lazy-init="true"/>
指定作用域:prototype(
每次从spring容器中取出新的对象)
<bean id="personService" class="com.jary.service.impl.PersonServiceBean
" scope="prototype"/>
spring的依赖注入三种方式
第一种:构造器注入(最常用)
第二种:使用属性的setter方法注入
第三种:使用Field注入(采用注解方式)
注入依赖通常采用手工装配和自动装配,建议采用手工装配方式,因为自动装配可能会产生无法预见的结果
spring的依赖注入装配
引用类型
二种方法
在配置文件beans.xml配置bean
第一种:注入其他bean,使用ref来指定那个bean(实际开发中,使用此方法)
把要注入对象personDao(
基于接口实现的bean)注入personService(
基于接口实现的bean)中
<bean id="
personDao1" class="com.jary.service.impl.PersonDaoBean" >
<bean id="personService" class="com.jary.service.impl.PersonServiceBean" />
<property name="personDao" ref="personDao1"></property>
</bean>
第二种:使用内部bean,但该bean不能被其他bean使用
把要注入对象personDao(
基于接口实现的bean)注入personService(
基于接口实现的bean)属性内部
<bean id="personService" class="com.jary.service.impl.PersonServiceBean" />
<property name="personDao">
<bean class="com.jary.service.impl.PersonDaoBean" >
</property>
</bean>
spring的依赖注入装配基本类型的方法
<bean id="personDao1" class="com.jary.service.impl.PersonDaoBean" >
<bean id="personService" class="com.jary.service.impl.PersonServiceBean" />
<construtor-arg index="0" type="java.lang.string" value="xxx" /> //构造器参数注入,index表示构造器参数第几个,type表示参数的类型 value表示基本类型
<construtor-arg index="0" type="java.lang.string" ref="
personDao1" /> //构造器参数注入,index表示构造器参数第几个,type表示参数的类型,ref表示引用类型
<property name="name" value="j
aryle
" /> //属性setter注入
spring的依赖注入装配集合类型的方法
set集合的注入 Set set= new HashSet();
<bean id="personService" class="com.jary.service.impl.PersonServiceBean" />
<property name="sets"
>
<set>
<value> 第一个</value>
<value>
第二个</value>
<value>
第三个</value>
</set>
</property>
List集合的方式 List list = new ArraryList();
<bean id="personService" class="com.jary.service.impl.PersonServiceBean" />
<property name="lists"
>
<list>
<value> 第一个</value>
<value>
第二个</value>
<value>
第三个</value>
</list>
</property>
Map集合的方式Map map=new HashMap();
<bean id="personService" class="com.jary.service.impl.PersonServiceBean" />
<property name="maps"
>
<map>
<entry key="key1" value="value1" />
<entry key="key2" value="value2" />
<entry key="key3" value="value3" />
</map>
</property>
spring依赖注入采用注解的方式手工装配bean对象(使用前提是标注在字段和setter方法上)
需要在spring配置文件beans.xml加入注解的一些约束文件和配置注解的打开
<context:annocation-config /> //配置注解的打开
@Autowired和@Resource注解进行装配,二者的区别是@Autowired默认按类型装配,@Resource默认是按照名称装配,当找不到与名称匹配的bean就会按照类型装配。
注意:建议使用@Resource进行装配,它是javaee中的包,而@Autowired是spring提供的注解包,扩展性没有前者好
@Autowired默认情况下要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false,如果想使用按照名称装配,可以结合@Qualifier注解一起使用,如下:
@Autowired @Qualifier("personDaoBean")
private PersonDao personDao;
@Resource注解和@Autowired一样,亦可以标注在字段和setter方法上,但是它默认按照名称装配,名称可以通过它的name属性来指定,
spring的自动装配,了解就行,不建议使用(会出现不可预知的结果)
spring容器自动扫描和管理bean(掌握)
通过在classpath自动扫描方式把组件纳入spring容器中管理
使用自动扫描的重要性:如果我们都是有xml的bean定义来配置组件,在一个稍大的项目中,通常会有上百个组件
显然会增加配置文件的体积,查找和维护起来不太方便,所以才引入在类路径下寻找标注了@Component(泛指组件,当组件不好归类时,使用此组件)、@Service(标注业务层相当于mvc中model)、 @Controller(标注控制层组件相当于struts2中action)、@Repository(标注数据访问组件即dao组件)注解的类,并把它们纳入spring容器中管理,我们只需要在beans.xml配置中打开自动扫描<context:component-scan base-package="cn.itcast" />
实例代码:
@Service("personService"(可以自定义名称,默认是类名PersonServideBean)) @scope("prototype"(作用域范围))
public class PersonServiceBean implements PersonService{
}
还有二个注解可以起到在,<bean init-method="" destory-method="" />
一个是bean被实例化之前执行初始化某个方法@PostConstruct(相当于init-method)
例如:@PostConstruct
public void init(){
System.out.println("初始化");
}
另外一个是在bean销毁之前执行的注解@PreDestory(相当于destory-method)
spring AOP技术(Proxy代理对象)(权限控制使用最多)(掌握)
具体实现:拦截所有的业务方法
判断是否有权限,有则通过,否则反之
动态代理Proxy是创建的代理对象依赖于目标对象实现了接口来实现的。如果目标对象没有接口实现spring提供了第三方框架CGlib
动态代理创建代理工厂,有代理工厂生成代理对象,
创建代理工厂 代码片段如下:
public class ProxyFactory implements InvocationHandler{
private Object targetObject;//目标对象
public Object createProxyIntance(Object targetObject){
this.targetObject=targetObject;
Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),this.targetObject.getClass().getInterfaces(),this);
//由于实现了InvocationHandler接口,就实现它所有方法
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
Object result=method.invoke(targetObject,args);
}
}
}
spring中的AOP面向切面编程(重点掌握)
首先了解一下AOP中的概念
Aspect(切面):横切性关注点的抽象即为切面,它与类相似,只是二者的关注点不一样,类是对物体特征的抽象,而切面是横切性关注点的抽象
joinpoint(连接点):那些被拦截到的点,在spring中这些点指的是方法,因为spring只支持方法类型的连接点,实际上,joinpoint还可以是field和类构造器
Pointcut(切入点):对那些joinpoint进行拦截的定义
Advice(通知):拦截到joinpoint之后所要做的事情就是通知,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知。
Target(目标对象):代理的目标对象
Weave(织入):指将aspect应用到target对象并导致proxy对象创建的过程即是织入。
Introduction(引入):在不修改类代码的前提下,Introduction可以在运行期为类动态的添加一些方法和field。
利用spring来实现AOP切面编程
还要在spring配置文件beans.xml中<aop:aspectj-autoproxy />
基于注解方式声明切面
@Aspect
public class Logprint{
@Pointcut("execution(* com.jary.service..*.*(..))");//对com.jary.service包下面的子包以及子包下面的所以方法进行拦截
private void anyMethod(){}//声明一个切入点
@Before("anyMethod")//定义前置通知,在拦截方法执行前执行
public void doAccessCheck(){ System.out.println("前置通知")}
@AfterReturning("anyMethod")//通知都是基于一个切入点定义的方法(anyMethod)展开的
public void doAfterReturning(){ System.out.println("后置通知")}//在拦截方法执行后执行
@After("anyMethod")
public void doAfter(){System.out.println("最终通知")} //在后置通知之后执行
@AfterThrowing("anyMethod")//异常通知,发生异常的时候才会执行
public void doAfterThrowing(){System.out.println("异常通知")}//上图可以看出当异常通知执行时,后置通知将不会被执行,前置通知,最终通知还是会执行
@Around("anyMethod")//环绕通知可以实现上面的所有通知
public Object doBasicProfiling( ProceedingJoinPoint pjp) throw Throwable{
//环绕通知对于权限的设定首选
//if(){//判定用户是否有权限
System.out.println("进入方法");
Object result=pjp.proceed();//固定格式,必须执行此方法
System.out.println("退出方法");
return result;
}
}
上图中在前置通知中获取方法的参数,在后置通知中获取有返回值的方法的返回值
基于XML配置文件来进行AOP编程
我们可以根据拦截切入点表达式来拦截特定的业务方法,例如:
上面的表达式只能拦截业务方法参数为string类型的方法
上面的表达式只能拦截业务方法没有返回值的方法
spring的事物管理(重点掌握)
基于注解开发的事务管理(掌握,项目中大多使用注解方式管理事务,可以精确定位到业务方法上,比较灵活),在配置文件中加入如下图所示:注解方式开启事务管理器
如果想把事物交给spring管理,就在业务bean类上加入@Transactional来实现
默认情况下,spring管理事务时,当业务方法抛出运行期异常RuntimeException(也叫unchecked)是回滚事务的,如下图:
但是当业务方法抛出Exception异常时(checked),不回滚事物,如下图:
我们也可手工配置强制方法抛出Exception异常时(checked),回滚事物的实现方法
在业务方法上加入@Transational(rollbackFor=Exception.class)
如下图
同理我们也可以使用手动强制方法抛出RuntimeException运行期例外不回滚事物,实现方法
在业务方法上@Transational(norollbackFor=RuntimeException.class),如下图所示:
spring容器中有些业务方法不需要开启事物,例如查询方法,可以使用事务的传播行为(propagation属性)来实现,
@Transational(propagation=Propagation.NOT_SUPPORTED)
如下图所示:
事物的传播属性有以下几种,默认事物传播属性是:REQUIRED
spring容器中的业务方法开启事务,当事务并发时,要设置事物的隔离级别 @Transational(isolation事物的隔离级别属性=repeatable read),这个级别和数据库系统有关,和spring容器无关,mysql数据库默认隔离级别为repeatalbe read(可重复读),级别蛮高的
基于xml配置文件管理事务(掌握),id=txManager的bean是事务管理器,这里利用AOP来拦截一些符合要事物管理的业务方法,然后通过通知<tx:advice id="txAdvice" transation-manager="txManager" >来为我们的业务bean配置业务方法的行为<tx:method name="get.*" read-only="true" propagation="NOT_SUPPORTED" />(配置业务方法为get开头的事务为只读,并且不开启事务)
<tx:name="*" />(配置其他业务方法为默认的事务传播行为REQUIRED)