Spring框架知识复习之二
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架知识复习之二相关的知识,希望对你有一定的参考价值。
Spring使用注解对Bean进行管理
1 使用注解需配置aop相关xsd文件的约束和命名空间
xsd文件名为:spring-aop-4.2.xsd
2 注解组件扫描配置
示例如下:base-package属性 设置扫描指定包下的所有子孙包
<context:component-scan base-package="cn.itma.bean"></context:component-scan>
3 spring管理bean的常用注解
<1>作用在类上的 用于创建对象的 @Component组件注解 的三个衍生注解(功能一致)
* @Controller :WEB层
* @Service:业务层
* @Repository:持久层
示例如下
注解书写:
package xxx.yyy.test;
@Component("user")
@Scope(scopeName="prototype")
public class User{
}
对应的xml配置书写:
<bean name="user" class="xxx.yyy.test.User" scope="prototype"/>
<2> 用于属性注入的注解 (使用注解注入的方式,可以不用提供set方法)
* @Value:用于注入普通类型
* @Autowired:自动装配(默认按类型进行装配)
存在的问题:
如果匹配多个类型一致的对象,将无法选择具体注入哪一个对象,
需要加一个注解辅助,声明它要注入哪一个Car对象
* @Qualifier:强制按照名称进行注入。
存在的问题:
如果存在多个名称一致的,类型不一致的对象,将无法准确匹配到。
* @Resource:相当于@Autowired和@Qualifier一起使用
示例如下
注解书写:
public class User{
@Value("flower")
private String name;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
@Resource(name="car")
private Car c;
}
对应的xml配置书写:
<bean name="user" class="xxx.yyy.User">
<property name="name" value="flower"/>
<property name="car" ref="car"></property>
</bean>
<bean name="car" class="xx.bean.Car">
<property name="name" value="dd"></property>
<property name="color" value="black"></property>
</bean>
<3>Spring整合junit测试的 注解
* 导入的包为:spring-test-4.2.4.RELEASE.jar
* @RunWith(SpringJUnit4Cla***unner.class) --帮我们创建容器
* @ContextConfiguration("classpath:applicationContext.xml") --指定创建容器使用哪个配置文件
<4>设置Bean作用范围的注解
@Scope:
* singleton:单例
* prototype: 多例
<4>设置Bean生命周期的注解
@PostConstruct:相当于init-method
@PreDestroy:相当于destroy-method
示例如下
注解书写:
public class User{
@PostConstruct
public void init(){
syso("这里是初始化方法");
}
@PreDestroy
public void destroy(){
syso("这里是销毁方法")
}
}
对应的xml配置书写:
<bean name="user" class="xxx.yyy.User" init-method="init" destroy-method="destroy">
</bean>
4 spring管理bean的xml方式与注解方式对比
xml配置 注解配置
(1)bean的创建和定义 <bean id="" class=""/> @Component(三个衍生:Controller,Service,Repository)
(2)bean名称的指定 通过id或name指定 @Component("person")
(3)bean中参数的注入 通过<property>或p命名空间 @Autowired(按类型注入)或@QUalifier(按名称注入)或Resource(两者相加)
(4)bean生命周期和 通过设置Scope属性,包括: singleton和prototype @Scope(scopeName="singleton")作用范围的设置
总结:
xml结构清晰,注解开发方便,所以实际开发中有一种xml和注解开发(Bean有XML配置,但使用的属性用注解注入)。
5 Spring和AOP面向切面编程
1 AOP概述
AOP(aspect oriented Programming面向切面编程),AOP是OOP(面向对象编程)的延续,
也是Spring框架的一个重要内容,spring利用AOP可以对业务逻辑各个部分进行隔离,
降低业务逻辑之间的耦合性,提供程序的重用性和开发效率。
2 Spring中AOP的主要功能
在不修改源码的基础上,对程序进行增强,可进行权限校验,日志记录,性能监控,事务控制。
3 Spring的AOP底层实现
两种代理机制:
* JDK的动态代理:针对实现了接口的类产生代理
示例:
//手动实现动态代理--演示(针对的是代理对象和被代理对象的实现同一接口)
public class UserServiceProxyFactory implements InvocationHandler {
private UserService us;
public UserServiceProxyFactory() {super();}
public UserServiceProxyFactory(UserService us) {super();this.us = us;}
public UserService getUserServiceProxy() {
//生成 UserService动态代理对象
UserService usProxy=(UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
UserServiceImp.class.getInterfaces(),
this);
//返回
return usProxy;
}
//下面为动态代理对象 对原对象的方法加强
@Override
public Object invoke(Object arg0, Method method, Object[] arg2) throws Throwable {
System.out.println("打开事务");
Object invoke = method.invoke(us,arg2);
System.out.println("提交事务");
return invoke;
}
}
* Cglib的动态代理:针对没有实现的接口的类产生代理,应用的是底层字节码增强技术,生成当前类的子类对象。
示例:
//通过第三方实现 代理技术--cglib技术(针对的是代理对象和被代理对象的继承关系)
public class UserServiceProxyFactory2 implements MethodInterceptor{
private UserService us;
public UserServiceProxyFactory2(UserService us) {super();this.us = us;}
public UserServiceProxyFactory2() {super();}
public UserService getUserServiceProxy() {
Enhancer en=new Enhancer(); //帮我们生成代理的对象
en.setSuperclass(UserServiceImp.class); //设置对谁进行代理
en.setCallback(this); //指定代理对象 要增强什么功能(代理要做什么)
UserService us = (UserService) en.create(); //创建代理对象
return us;
}
@Override
public Object intercept(Object proxyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
//打开事务
System.out.println("打开事务");
//调用原有方法
Object returnValue = methodProxy.invokeSuper(proxyobj,arg);
//提交事务
System.out.println("提交事务");
return returnValue;
}
}
4 Spring基于AspectJ的AOP开发
(1)Spring的AOP开放相关术语:
<1>Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
<2>Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
& execution()切入点表达式的基本语法:
* 基本格式:execution( [方法访问修饰符] 方法返回值 全类名.方法名(方法参数))
* 配置方法名的不同形式:
public void cn.itheima.service.UserServiceImp.save() 简单形式
void cn.itheima.service.UserServiceImp.save() public可省略
* cn.itheima.service.UserServiceImp.save() *代表任意的返回值类型
* cn.itheima.service.UserServiceImp.*() *()代表该目标对象下的所有方法
* cn.itheima.service.UserServiceImp.*(..) *(..)对方法参数不作任何要求(空参和实参都行)
//下面为开发常用形式
* cn.itheima.service.*ServiceImp.*(..) *ServiceImp代表名称包含 ServiceImp的目标对象(是开发的标准形式)
* cn.itheima.service..*ServiceImp.*(..) ..*ServiceImp 代表 在包括service下的子孙包中的 名称包含 ServiceImp的目标对象
& 配置AOP切入点示例:
<aop:config>
id属性:为切入点命名
<aop:pointcut expression="execution(* cn.ith.service.*ServiceImp.*(..))" id="pc"/>
</aop:config>
<3>Advice(通知/增强):
所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.
通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
有一种特殊的通知:Introduction(引介)
不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
通知类型详解
前置通知(before):在目标方法执行 之前.
后置通知(afterReturning) :在目标方法执行 之后,如果出现异常则不会调用
环绕通知(around) :在目标方法执行 前和后
异常抛出通知(afterException):在目标方法执行 出现异常的时候 执行
最终通知(after) :无论目标方法是否出现异常 最终通知都会 执行 .
<4>Aspect(切面): 是切入点和通知(引介)的结合
配置切面:
<!-- 属性ref:要关联的 通知 名称 -->
<!--2.配置通知对象(目标对象的增强版)-->
<bean name="myAdvice" class="cn.itheima.d_aspect.MyAdvice"></bean>
<aop:aspect ref="myAdvice">
<!-- method属性:设置方法名 pointcut-ref:设置要关联的 切点名称-->
<!--指定名为before为前置通知-->
<aop:before method="before" pointcut-ref="pc"/>
<!--指定名为afterReturning为后置通知(出现异常不会调用) -->
<aop:after-returning method="afterReturning" pointcut-ref="pc"/>
<!--指定名为around为环绕通知 -->
<aop:around method="around" pointcut-ref="pc"/>
<!--指定名为afterException为异常拦截通知 -->
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<!--指定名为after为后置通知(是否出现异常都会调用) -->
<aop:after method="after" pointcut-ref="pc"/>
</aop:aspect>
<5>Target(目标对象):代理的目标对象
<6>Weaving(织入):
是指把增强应用到目标对象来创建新的代理对象的过程。
spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入.
AspectJ是一个面向切面的框架,它定义了AOP语法,扩展了Java语言。
<7>Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
(2)Spring使用AspectJ进行AOP开发
<1>要导入相关的jar包,如下
* spring传统aop开发包:
spring-aop-4.2.4.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
* aspectJ开发包:
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
<2>导入aop约束
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
<3>配置xml方式实现AOP的代码示例
示例需求:对一个UserServiceImpl类 进行AOP增强 其save()方法
* UserService类(目标对象)
public interface UserService {void save();}
public class UserServiceImp implements UserService {
@Override
public void save() {
System.out.println("保存");
}
}
* MyAdvice(通知对象)
public class MyAdvice {
public void before() {
System.out.println("前置通知!");
}
public void afterReturning() {
System.out.println("后置通知!(如果出现异常则不会调用)");
}
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("这是环绕通知之前的部分!");
Object proceed = pjp.proceed(); //调用目标方法
System.out.println("这是环绕通知之后的部分!");
return proceed;
}
public void afterException() {
System.out.println("出现异常了!");
}
public void after() {
System.out.println("另一个后置通知(目标方法运行之后调用,无论是否出现异常都会调用)");
}
}
* AOP相关配置
<!--1.配置目标对象 -->
<bean name="userService" class="cn.ith.service.UserServiceImp"></bean>
<!--2.配置通知对象(目标对象的增强版)-->
<bean name="myAdvice" class="cn.it_aspect.MyAdvice"></bean>
<!--3.配置将通知织入目标对象 -->
<aop:config>
配置切入点
<aop:pointcut expression="execution(* cn.itheima.service.*ServiceImp.*(..))" id="pc"/>
配置切面(切点+通知)
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="pc"/>
<aop:after-returning method="afterReturning" pointcut-ref="pc"/>
<aop:around method="around" pointcut-ref="pc"/>
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<aop:after method="after" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
* 测试类代码
@RunWith(SpringJUnit4Cla***unner.class)
@ContextConfiguration("classpath:cn/itheima/d_aspect/applicationContext.xml")
public class Demo {
//将名为 userService的目标对象注入到 us成员变量中
@Resource(name="userService")
private UserService us;
@Test
public void fun1() {
us.save();
}
}
* 结果对比
未使用AOP时调用UserService的save方法,结果为 :输出 "保存"字符串
使用了AOP后,字符串输出结果为:
前置通知!
这是环绕通知之前的部分!
保存
另一个后置通知(目标方法运行之后调用,无论是否出现异常都会调用)
这是环绕通知之后的部分!
后置通知!(如果出现异常则不会调用)
<4>注解方式 实现AOP的代码示例
示例需求:对一个UserServiceImpl类 进行AOP增强 其save()方法
* UserService类(目标对象)
public interface UserService {void save();}
public class UserServiceImp implements UserService {
@Override
public void save() {
System.out.println("保存");
}
}
* MyAdvice(通知对象)
//注入切面
@Aspect
public class MyAdvice {
//注入切点
@Pointcut("execution(* cn.itheima.service.*ServiceImp.*(..))")
//空参方法名pc作为 该切点的id
public void pc(){}
//注入前置通知,并指定切入点
//@Before("execution(* cn.itheima.service.*ServiceImp.*(..))")
@Before("MyAdvice.pc()") //简写
public void before() {
System.out.println("前置通知!");
}
//注入后置通知,并指定切入点
@AfterReturning("execution(* cn.itheima.service.*ServiceImp.*(..))")
public void afterReturning() {
System.out.println("后置通知!(如果出现异常则不会调用)");
}
//注入环绕通知,并指定切入点
@Around("execution(* cn.itheima.service.*ServiceImp.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("这是环绕通知之前的部分!");
Object proceed = pjp.proceed(); //调用目标方法
System.out.println("这是环绕通知之后的部分!");
return proceed;
}
//注入异常拦截通知,并指定切入点
@AfterThrowing("execution(* cn.itheima.service.*ServiceImp.*(..))")
public void afterException() {
System.out.println("出现异常了!");
}
//注入后置通知,并指定切入点
@After("execution(* cn.itheima.service.*ServiceImp.*(..))")
public void after() {
System.out.println("另一个后置通知(目标方法运行之后调用,无论是否出现异常都会调用)");
}
}
* AOP内的配置内容
<!--1.配置目标对象 -->
<bean name="userService" class="cn.itma.service.UserServiceImp"></bean>
<!--2.配置通知对象 -->
<bean name="myAdvice" class="cn.ithnotationAop.MyAdvice"></bean>
<!-- 开启使用注解完成织入 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
以上是关于Spring框架知识复习之二的主要内容,如果未能解决你的问题,请参考以下文章