spring

    xiaoxiao2022-07-14  174

    Spring

    工具使用导入相关包增加配置文件配置bean注入方式引用其他bean特殊赋值集合赋值自动装配继承依赖作用域配置外部属性文件SpELbean的生命周期bean的后置处理器获取bean通过类全类名基于反射获取利用静态工厂方法来获取bean利用实例工厂来创建bean通过FactoryBean 注解基本使用自动装配泛型依赖注入示例 spring AOPAOP术语基于注解对于六种术语的解释对于五种通知类型的解释Before 前置通知After 后置通知AfterThrowing 异常通知AfterReturning返回通知Around 环绕通知几种通知的比较 AspectJ表达式切面优先级重用切点 基于配置文件 Spring事务基于xml基于注解注意事务的传播行为事务的隔离级别异常回滚超时跟只读 整合hibernate整合struts2

    工具

    建议直接下载最新版包含sts的eclipse,可以去https://spring.io/tools

    使用

    导入相关包

    增加配置文件

    在eclipse中直接new一个spring bean configuration file;

    配置bean

    注入方式

    构造器注入/set注入 public class HelloWorld { private String name; private String age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public HelloWorld(String age) { super(); this.age = age; } @Override public String toString() { return "HelloWorld [name=" + name + ", age=" + age + "]"; } public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld bean = context.getBean("helloWorld",HelloWorld.class); System.out.println(bean); } } <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helloWorld" class="com.huzd.study01.HelloWorld"> <constructor-arg name="age" value="StringConstructor"></constructor-arg> <property name="name" value="String"></property> </bean> </beans> 注意:set注入,name对应bean的属性,value就是属性值;注意:构造器注入,name对应参数名,value对应参数值,对应参数列表:参数个数,类别,顺序,其中参数个数是由construct标签的个数决定,参数类别可以由type属性决定,参数顺序可以由index来标记或者由name属性对应参数名称;注入中有特殊标记,例如“>”这种尖括号,可以使用<![CDATA[标记]]> 直接使用会报错 使用CDATA标签即可

    引用其他bean

    在标签中使用ref属性即可 使用内部bean,注意内部bean可以不要id,只能内部使用,不能外部引用;

    特殊赋值

    赋值null 级联赋值 外部bean级联 内部bean级联 注意:由内部bean的级联可以,级联的方式是由属性名引用赋值,而并非使用外部或者内部bean的id名称赋值;

    集合赋值

    list赋值(可以内部bean,也可以引用) <bean id="person" class="com.huzd.study01.Person"> <property name="cars"> <list> <bean class="com.huzd.study01.Car"> <property name="speed" value="100"></property> </bean> <bean class="com.huzd.study01.Car"> <property name="speed" value="200"></property> </bean> <bean class="com.huzd.study01.Car"> <property name="speed" value="300"></property> </bean> </list> </property> </bean> map赋值 <bean id="car1" class="com.huzd.study01.Car"> <property name="speed" value="100"></property> </bean> <bean id="car2" class="com.huzd.study01.Car"> <property name="speed" value="200"></property> </bean> <bean id="car3" class="com.huzd.study01.Car"> <property name="speed" value="300"></property> </bean> <bean id="person" class="com.huzd.study01.Person"> <property name="carMap"> <map> <entry key="car1" value-ref="car1" ></entry> <entry key="car2" value-ref="car2" ></entry> <entry key="car3" value-ref="car3" ></entry> </map> </property> </bean> properties赋值 <bean id="dataSource" class="com.huzd.study01.DataSource"> <property name="properties"> <props> <prop key="user">root</prop> <prop key="password">123456</prop> <prop key="url">jdbc</prop> <prop key="driver">driverclass</prop> </props> </property> </bean> 配置单独的集合bean <util:list id="cars"> <ref bean="car1"/> <ref bean="car2"/> <ref bean="car3"/> </util:list> <bean id="person" class="com.huzd.study01.Person"> <property name="cars" ref="cars"></property> </bean> 利用p命名空间简化配置 <bean id="person1" class="com.huzd.study01.Person" p:name="huzd" p:age="111" p:cars-ref="cars"></bean>

    自动装配

    在bean的标签中指定autowire属性,spring中id跟name区别,前提是必须生成set方法; byName:根据bean的名称来自动装配,由于id跟name都只能唯一,故此方法获取bean唯一byType:根据bean的class类型来进行自动装配

    继承

    使用parent让子bean来继承父bean,并且在子bean中还可以覆盖父bean属性 <bean id="person" class="com.huzd.study02.autowire.Person" p:name="huzd" ></bean> <bean id="car" class="com.huzd.study02.autowire.Car" p:speed="1000"></bean> <bean id="person2" parent="person" p:name="huzd1"></bean> 在父bean中增加abstract属性为true可以让父bean只用来被继承而不能被实例化,若一个bean的class属性没有被指定,则该bean只能是抽象bean

    依赖

    使用depends-on属性来指定依赖bean(用逗号分隔多个bean) <bean id="person" class="com.huzd.study02.autowire.Person" p:name="huzd" depends-on="car" ></bean> <bean id="car" class="com.huzd.study02.autowire.Car" p:speed="1000"></bean> 假设car这个bean不存在则启动报错,避免赋空值

    作用域

    可参考

    通过配置scope来配置 singleton(默认):单例,在初始化spring容器的时候就已经初始化了bean,以后所有的请求都返回相同的bean对象;prototype:在使用的时候才会创建bean,并且每次使用都会创建新bean,相当于new一个bean

    配置外部属性文件

    在spring配置文件中引入context命名空间,并配置location为外部配置文件,然后在使用中使用${}来获取即可;

    bean.properties

    name=huzd

    applicationContext.xml

    <context:property-placeholder location="classpath:bean.properties"/> <bean id="person" class="com.huzd.study02.autowire.Person" p:name="${name}"></bean>

    SpEL

    显示常量:#{‘常量值’},主要括号中需要用单引号或者双引号引起来 <bean id="person" class="com.huzd.study02.autowire.Person" p:name="#{'huzd'}"></bean> 显示静态类的方法或者属性:#{T(方法全类名).method()} <bean id="car1" class="com.huzd.study02.autowire.Car" p:speed="#{T(java.lang.Math).random()}"></bean> 显示其他bean或者其他bean属性 <bean id="person" class="com.huzd.study02.autowire.Person" p:name="#{'huzd'}" p:car="#{car2}"></bean> <bean id="car2" class="com.huzd.study02.autowire.Car" p:speed="#{car1.speed}"></bean> 使用运算符 <bean id="car3" class="com.huzd.study02.autowire.Car" p:speed="#{300}"></bean> <bean id="person" class="com.huzd.study02.autowire.Person" p:name="#{'huzd'}" p:car="#{car3}" p:info="#{car3.speed > 30 ? '大人物':'普通小伙计'}"></bean>

    bean的生命周期

    调用bean的构造器或者工厂方法创建bean实例对象调用bean的set方法根据配置设置属性值如果实现了BeanNameAware,BeanFactoryAware等接口,则注入相应的属性调用BeanPostProcessor的postProcessBeforeInitialization方法调用InitializingBean的afterPropertiesSet方法调用自定义的init方法调用BeanPostProcessor的postProcessAfterInitialization方法bean准备就绪,可以使用调用DispostbleBean的destory方法调用自定义 destroy方法

    bean的后置处理器

    实现beanPostProcessor接口 public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("before"); return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName); } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("after"); return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName); } } 在配置文件中配置 <bean class="com.huzd.study02.spel.MyBeanPostProcessor"></bean> 最终效果:可以在init前后处理bean注意: 由于BeanPostProcessor是对所有bean都会生效,所以在方法内部需要用beanName来判断具体哪个bean再处理在配置文件中如果配置多个实现了BeanPostProcessor接口的类,则会相应的执行多次方法;

    获取bean

    通过类全类名基于反射获取

    即直接在spring配置文件中配置class属性获取bean

    利用静态工厂方法来获取bean

    配置静态工厂类 public class StaticCarFactory { private static Map<String,Car> cars = new HashMap<String, Car>(); static { cars.put("car", new Car(1000)); } public static Car getCar(String name) { return cars.get(name); } } 配置文件:class指向工厂类,配置的是bean实例,factory-method指向静态工厂方法,如果有参数通过constructor-arg来传入; <bean id="car1" class="com.huzd.study03.factory.StaticCarFactory" factory-method="getCar"> <constructor-arg value="car"></constructor-arg> </bean>

    利用实例工厂来创建bean

    创建实例工厂 public class InstanceFactory { private Map<String, Car> cars = null; public InstanceFactory() { cars = new HashMap<String, Car>(); cars.put("car", new Car(2000)); } public Car getCar(String name) { return cars.get(name); } } 配置文件:首先需要配置工厂bean实例,然后配置car的实例,配置factory-bean属性指向工厂bean,factory-method指向获取bean的方法,有参数依旧由constructor-arg传入 <bean id="carFactory" class="com.huzd.study03.factory.InstanceFactory"></bean> <bean id="car2" factory-bean="carFactory" factory-method="getCar"> <constructor-arg name="name" value="car"></constructor-arg> </bean>

    通过FactoryBean

    配置类实现FactoryBean接口 public class CarFactoryBean implements FactoryBean<Car> { @Override public Car getObject() throws Exception { return new Car(3000); } @Override public Class<?> getObjectType() { return Car.class; } @Override public boolean isSingleton() { return true; } } 配置文件直接配置car实例bean并且class指向FactoryBean即可,上面两种都需要指定方法,这个接口配置之后,默认调用实现类的getObject获取car实例 <bean id="car3" class="com.huzd.study03.factory.CarFactoryBean"></bean>

    注解

    基本使用

    基本的4个注解 Component:组件Repository:一般用来标记持久层Service:一般用来标记服务层Controller:一般用来标记表现层 配置完成之后需要在配置文件中配置包扫描:base-package用来指定要扫描哪些包,resource-pattern用来匹配特定包或者类 <context:component-scan base-package="com.huzd.study03.annotation" resource-pattern="dao/*.class" ></context:component-scan>

    通过默认类名第一个字母小写的方式获取或者使用注解的value属性配置

    如下:配置repository的UserDaoImpl类可以通过userDaoImpl获取

    @Repository public class UserDaoImpl implements UserDao { @Override public void add() { System.out.println("save"); } } public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext3.xml"); UserDaoImpl userDaoImpl = context.getBean("userDaoImpl",UserDaoImpl.class); userDaoImpl.add(); } }

    或者通过使用value属性来配置

    @Repository(value = "userDao") public class UserDaoImpl implements UserDao { @Override public void add() { System.out.println("save"); } } public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext3.xml"); UserDaoImpl userDaoImpl = context.getBean("userDao",UserDaoImpl.class); userDaoImpl.add(); } }

    在context:component-scan内部配置子标签context:exclude-filter

    annotation类型排除:表示排除所有以Repository这个注解的bean <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/> annotation类型包含:表示只包含Repository这个注解的bean,需要注意的是,需要在父标签context:component中配置use-default-filters="false",可以理解成,默认配置为true是扫描用的默认过滤器扫描包下所有文件,配置context:exclude-filter标签会从所有文件中过滤掉某些文件(交集),但是context:include-filter会扫描某些文件(并集),最终得到的跟还是所有文件都扫描,所以需要关掉默认过滤器才有效果; <context:component-scan base-package="com.huzd.study03.annotation" resource-pattern="dao/*.class" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/> </context:component-scan> 接口类型排除:设置type为assignable,expression为某一接口类,则通过该接口实现的类都排除 <context:exclude-filter type="assignable" expression="com.huzd.study03.annotation.dao.UserDao"/> 接口类型包括:设置type为assignable,expression为某一接口类,则通过改接口实现的类都可以获取到 <context:component-scan base-package="com.huzd.study03.annotation" resource-pattern="dao/*.class" use-default-filters="false"> <context:include-filter type="assignable" expression="com.huzd.study03.annotation.dao.UserDao"/> </context:component-scan>

    自动装配

    在构造器,字段,方法上面都可以使用@Autowired来注入相应值(构造器跟方法注入的是会注入相同参数名称类型的bean)默认情况下Autowired如果找不到装配的类会报错,可以摄者required属性为false不报错(为null)当有过个兼容类型的bean是,自动装配会报错,一种解决方案是将需要注入的类设置成跟注入的属性名称一致(autowire会先byType再byName,直到找到唯一一个),另外一种方式是使用@Qualifier属性将bean微调注入

    UserServiceImpl类

    @Service public class UserServiceImpl implements UserService { UserDao UserDao; @Override public void add() { UserDao.add(); } }

    UserServiceImpl2

    @Service public class UserServiceImpl2 implements UserService { UserDao UserDao; @Override public void add() { UserDao.add(); } }

    直接装配时,先byType会找到两个userService接口的类,再byName还是会找到userServiceImpl跟userServiceImpl2两个类(默认以类名第一个字母小写作为id),这样的话会报错,可以使用Qualifier注解将userServiceImpl微调成userService注入

    @Controller public class UserController { @Autowired @Qualifier("userServiceImpl") UserService userService; public void execute() { userService.add(); } }

    使用在方法中就是参数前微调

    @Controller public class UserController { UserService userService; @Autowired public void setUserService(@Qualifier("userServiceImpl") UserService userService) { this.userService = userService; } public void execute() { userService.add(); } } @Autowired也可以应用在数组,集合,map上面,放在数组上面就是匹配所有数组类型的类注入,放在集合上面就是匹配所有的集合类型的类注入,放在map上面,若map的键为String,则是以bean的id为key,bean本身作为value注入;

    泛型依赖注入

    一个泛型父类引用另外一个泛型父类,那么子类也会自动将同一个泛型对应依赖,但是如果有多个类型匹配则会报错;

    示例

    父类service泛型类引用BaseRepository泛型父类

    public class BaseService<T> { @Autowired protected BaseRepository<T> repository; public void add() { System.out.println("add"); System.out.println(repository); } }

    父类BaseRepository泛型类

    public class BaseRepository<T> { }

    具体UserService 类继承BaseService并设置泛型为User

    @Service public class UserService extends BaseService<User> { }

    具体UserRepository 继承BaseRepository并设置泛型为User,此时UserService 就自动依赖上了UserRepository

    @Repository public class UserRepository extends BaseRepository<User> { }

    若还有另外一个也是设置User泛型,则会报错;

    @Repository public class UserRepository2 extends BaseRepository<User>{ }

    spring AOP

    AOP术语

    切面(aspect):需要插入的对象,例如日志切面;通知(advice):切面必须要完成的工作;目标(target):被通知的对象代理(proxy):向目标对象应用通知之后创建的对象连接点(joinPoint):程序执行的某个特定位置,由两个要素决定,方法跟方位(方法执行之前,之后,异常后等等)切点(pointCut):切面与业务逻辑相交的点,对应连接点根据方位不同,一个切点对应多个连接点

    基于注解

    在配置文件中增加配置 <!-- 让aspectJ注解起作用 自动生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> UserService中引用Userdao @Service public class UserService { @Autowired private UserDao userDao; public void save(User u) { System.out.println("save user"); userDao.add(u); } public void add(User u) { System.out.println("add User...."); } } @Repository public class UserDaoImpl implements UserDao { @Override public void add(User u) { System.out.println("add User...."); } } 新建切面,并设置before注解表示在某个方法之前执行,由org.aspectj.lang.JoinPoint可以获取方法信息 @Aspect @Component public class LoggingAspect { @Before("execution(public void com.huzd.study01.aop.UserService.*(User))") public void beforeAdd(JoinPoint joinpoint) { String methodName = joinpoint.getSignature().getName(); Object[] args = joinpoint.getArgs(); System.out.println("methodName:"+methodName); System.out.println("args:"+Arrays.asList(args)); System.out.println("before add..."); } }

    对于六种术语的解释

    切面:在AspectJ注解中,切面是一个带有@Aspect注解的java类通知:AspectJ支持五种类型的通知: @Before:前置通知,在方法执行之前执行@After:后置通知,在方法执行之后执行@AfterReturning:返回通知,在方法返回结果之后执行@AfterThrowing:异常通知,在方法返回异常之后执行@Around:环绕通知,围绕着方法执行 目标:例如上面UserService类代理:AOP容器生成的代理对象(在配置文件以标签声明)连接点:切面中的方法切点:目标中的方法

    对于五种通知类型的解释

    Before 前置通知

    在UserService的save方法执行之前执行beforeAdd方法

    @Before("execution(public void com.huzd.study01.aop.UserService.save(User))") public void beforeAdd(JoinPoint joinpoint) { String methodName = joinpoint.getSignature().getName(); Object[] args = joinpoint.getArgs(); System.out.println("methodName:"+methodName); System.out.println("args:"+Arrays.asList(args)); System.out.println("before add..."); }

    After 后置通知

    在UserService的save方法执行之后执行afterAdd方法

    @Aspect @Component public class LoggingAspect { @After("execution(public void com.huzd.study01.aop.UserService.save(User))") public void afterAdd(JoinPoint joinpoint) { String methodName = joinpoint.getSignature().getName(); Object[] args = joinpoint.getArgs(); System.out.println("methodName:"+methodName); System.out.println("args:"+Arrays.asList(args)); System.out.println("after add..."); } }

    AfterThrowing 异常通知

    在UserService的save方法抛出异常之后执行,需要注意的是,如果异常被捕获,则不会执行;

    @Aspect @Component public class LoggingAspect { @AfterThrowing("execution(public void com.huzd.study01.aop.UserService.save(User))") public void beforeAdd(JoinPoint joinpoint) { String methodName = joinpoint.getSignature().getName(); Object[] args = joinpoint.getArgs(); System.out.println("methodName:"+methodName); System.out.println("args:"+Arrays.asList(args)); System.out.println("after add..."); } }

    AfterReturning返回通知

    无论连接点是正常返回还是异常返回,后置通知都会执行,如果指向让正常返回才执行,可以用返回通知代替后置通知,在注解中通过设置returning = "result"还可以获取返回值

    @Aspect @Component public class LoggingAspect { //@AfterThrowing("execution(public void com.huzd.study01.aop.UserService.save(User))") //@After("execution(public void com.huzd.study01.aop.UserService.save(User))") @AfterReturning(value = "execution(public String com.huzd.study01.aop.UserService.save(User))",returning = "result") public void afterAdd(JoinPoint joinpoint,Object result) { String methodName = joinpoint.getSignature().getName(); Object[] args = joinpoint.getArgs(); System.out.println("methodName:"+methodName); System.out.println("args:"+Arrays.asList(args)); System.out.println("after add..."); System.out.println("result:"+result); } }

    Around 环绕通知

    其实就是类似动态代理,连接点必须有ProceedingJoinPoint 参数,并且需要调用proeed方法

    @Around(value = "execution(public String com.huzd.study01.aop.UserService.save(User))") public Object around(ProceedingJoinPoint pjd) throws Throwable { Object proceed = null; try { System.out.println("前置通知"); proceed = pjd.proceed(); System.out.println(1/0); System.out.println("返回通知"); } catch (Exception e) { System.out.println("异常通知"); } System.out.println("后置通知"); return proceed; }

    几种通知的比较

    因为AOP是利用的动态代理来实现,因此几种通知相当于在invoke中如下位置:

    @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub Object result = null; try { //前置通知 result = method.invoke(userDao, args); //返回通知 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); //异常通知 } //后置通知 return result; }

    AspectJ表达式

    execution(* *.*.*(. .)) 第一个*表示任意修饰符跟任意返回值 第二个*表示任意包 第三个*表示任意类 第四个*表示任意方法 最后括号表示方法,中间的..表示任意参数

    指向com.huzd.study01.aop这个包下的UserService这个类的具有public修饰符并且返回值为void,有一个User类型参数的save方法 execution(public void com.huzd.study01.aop.UserService.save(User)) 指向com.huzd.study01.aop这个包下的UserService这个类的具有public修饰符并且返回值为void,有任意参数的save方法 execution(public void com.huzd.study01.aop.UserService.save(..)) 指向com.huzd.study01.aop这个包下的UserService这个类的具有public修饰符并且返回值为void,有任意参数的任意方法 execution(public void com.huzd.study01.aop.UserService.*(..)) 指向com.huzd.study01.aop这个包下的任意类的具有public修饰符并且返回值为void,有任意参数的任意方法 execution(public void com.huzd.study01.aop.*.*(..)) 指向com.huzd.study01.aop这个包下的任意类的具有任意修饰符并且返回值任意类型,有任意参数的任意方法 execution(* com.huzd.study01.aop.*.*(..)) 指向任意包下的任意类的具有任意修饰符并且返回值任意类型,有任意参数的任意方法 execution(* *.*.*(..)) 指向任意包下的任意类的具有任意修饰符并且返回值任意类型,第一个参数为Int类型,后面为任意类型或数量参数的任意方法 execution(* *.*.*(Int,..)) 符合前面表达式或者符合后面表达式的方法(&&,!同理) execution(* *.*.*(..)) || execution(* *.*.*(..))

    切面优先级

    在class上实现Ordered接口或者使用@Order注解,getOrder()返回值或者是@Order的值越小则优先级越高;

    重用切点

    在切面中声明通知方法时,一个切点表达式可能会出现在多个通知中,使用@PointCut来将一个切点声明为普通方法,该方法通常是空的,因为将切点的定义与逻辑混淆是不合理的;

    将切点的定义定义成pointCut普通方法,方法可以由pointCut属性指定也可以由value属性指定,如果切点定义不在本类中,需要指定包名跟类名,例如com.huzd.study01.aop.LoggingAspect.getPointCut()

    @Aspect @Component public class LoggingAspect { //@AfterThrowing("execution(public void com.huzd.study01.aop.UserService.save(User))") //@After("execution(public void com.huzd.study01.aop.UserService.save(User))") @AfterReturning( pointcut = "com.huzd.study01.aop.LoggingAspect.getPointCut()",returning = "result") public void afterAdd(JoinPoint joinpoint,Object result) { String methodName = joinpoint.getSignature().getName(); Object[] args = joinpoint.getArgs(); System.out.println("methodName:"+methodName); System.out.println("args:"+Arrays.asList(args)); System.out.println("after add..."); System.out.println("result:"+result); } //@Around("getPointCut()") public Object around(ProceedingJoinPoint pjd) throws Throwable { Object proceed = null; try { System.out.println("前置通知"); proceed = pjd.proceed(); System.out.println(1/0); System.out.println("返回通知"); } catch (Exception e) { System.out.println("异常通知"); } System.out.println("后置通知"); return proceed; } @Pointcut(value = "execution(public String com.huzd.study01.aop.UserService.save(User))") public void getPointCut() {} }

    基于配置文件

    <?xml version="1.0" encoding="UTF-8"?> <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" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 配置服务类,拥有userDao引用 --> <bean id="userService" class="com.huzd.study01.aop.UserService" autowire="byName"></bean> <!-- 配置userDao类 --> <bean id="userDao" class="com.huzd.study01.aop.UserDaoImpl"></bean> <!-- 配置切面bean --> <bean id="logAspect" class="com.huzd.study01.aop.LoggingAspect"></bean> <!-- 配置aop --> <aop:config> <!-- 配置切点表达式 --> <aop:pointcut expression="execution(* com.huzd.study01.aop.*.*(..))" id="testOperation"/> <!-- 配置切面,并指向切面bean --> <aop:aspect id="loggingAspect" ref="logAspect" > <!-- 配置通知 --> <aop:before method="afterAdd" pointcut-ref="testOperation" /> </aop:aspect> </aop:config> </beans>

    Spring事务

    声明式事务有两种,基于xml跟基于注解

    基于xml

    首先构建数据源dataSource然后声明事务管理器声明事务通知声明aop配置

    基于注解

    声明事务管理器注解扫描包使事务注解生效<tx:annotation-driven/>然后再在需要添加事务的方法上增加@Transactional

    注意

    由于springAOP是基于代理的方法,所以只能增强公共方法,因此只有公共方法才能通过springAOP进行事务管理

    事务的传播行为

    基于注解:@Transactional(propagation=XXX) 基于xml:

    required(默认):如果外层方法有事务,那么内层方法直接使用外层方法的事务,因此,只要整个外层事务中有一个方法调用失败,那么整个外层事务都回滚了; required_new:外层方法有一个事务,内层方法自己独立开启事务,因内层方法事务互不影响,外层方法中若有一个事务回滚,只对其自己的事务生效;

    事务的隔离级别

    基于注解 基于xml

    异常回滚

    默认情况下,只有未检查异常会导致事务回滚,而受检查的不会,因此受检查异常需要自己捕获并重新抛出运行时异常,也可以使用rollbackFor或者noRollbackFor属性来定义 rollbackFor:遇到异常回滚 noRollbackFor:遇到异常不会滚;

    超时跟只读

    超时:事务在强制回滚之前,事务的占用时间;这样可以防止事务长时间占用资源只读:事务只是读取数据不会修改事务,帮助数据库引擎优化事务

    整合hibernate

    整合struts2

    在整合成web工程的时候,spring配置文件需要有web容器加载,因此需要在web.xml中配置

    <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:mybatis-spring/spring-config.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
    最新回复(0)