本文为原创投稿文,作者:像风一样
一、前言
Spring 有XML配置和注解两种版本,我个人非常喜欢使用注解,相当热衷Spring boot!
对于Spring,核心就是IOC容器,这个容器说白了就是把你放在里面的对象(Bean)进行统一管理,你不用考虑对象如何创建如何销毁,从这方面来说,所谓的控制反转就是获取对象的方式被反转了。
既然你都把对象交给人家Spring管理了,那你需要的时候不得给人家要呀。这就是依赖注入(DI)!再想下,我们在传入一个参数的时候除了在构造方法中就是在setter方法中,换个好听的名字就是构造注入和设值注入。
至于AOP(面向切面),这玩意我举个例子说下,比如你写了个方法用来做一些事情,但这个事情要求登录用户才能做,你就可以在这个方法执行前验证一下,执行后记录下操作日志,把前后的这些与业务逻辑无关的代码抽取出来放一个类里,这个类就是切面(Aspect),这个被环绕的方法就是切点(Pointcut),你所做的执行前执行后的这些方法统一叫做增强处理(Advice)。
二、配置
推荐使用IDEA快速构建Spring项目!
抛弃配置第一步,快速定义application.xml
?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: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"
!--开启自动扫描--
context:component-scan base-package="cn.zyzpp"/
/beans
作用
默认开启annotation注解配置,激活@Required,@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext, @PersistenceUnit组件类中的注释。
三、依赖注入
搜索Bean类
Spring提供如下几个Annotation来标注Spring Bean:
使用@Resource配置依赖
使用@Resource与
@Resource不仅可以修饰setter方法,也可以直接修饰实例变量,如果使用@Resource修饰实例变量将会更加简单,此时Spring将会直接使用JavaEE规范的Field注入,此时连setter方法都可以不要。
@Resource位于javax.annotation包下,是来自JavaEE规范的一个Annotation。
@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
使用@Autowired配置依赖
Spring提供了@Autowired注解来指定自动装配,@Autowired可以修饰setter方法、普通方法、实例变量和构造器等。当使用@Autowired标注setter方法时,默认采用byType自动装配策略。
默认情况下@Autowired(required = true),意思是要求依赖对象必须存在。
搭配@Qualifier指定BeanId
在这种策略下,符合自动装配类型的候选Bean实例常常有多个,这个时候就可能引起异常,为了实现精确的自动装配,Spring提供了@Qualifier注解,通过使用@Qualifier,允许根据Bean的id来执行自动装配。
@Autowired
@Qualifier(value = "user")
User user;
四、定义Bean
@Configuration配置
@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
@Configuration
public class AppConfig {
@Autowired
Environment env;
@Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
myBean.setName(env.getProperty("bean.name"));
return myBean;
}
}
@Bean定义
@Bean 与 Component 的区别是用在方法上 ,而不是类上。类似于XML中
如果需要显式命名,可以使用name属性(或value属性)。还要注意,name接受字符串数组,允许对单个bean使用多个名称(即主bean名称加上一个或多个别名)。
可以定义Bean的初始化方法与关闭应用程序时调用的方法。
@Bean({"b1", "b2"},initMethod = "",destroyMethod = "") // 有b1,b2 bean,但没有myBean
public MyBean myBean() {
return new MyBean;
}
@Scope作用域
@Scope可以搭配@Component等或者@Bean注解定义Bean的作用域。默认作用域 Singleton。
示例
@Component
@Scope(value = "singleton")
public class HelloWord {
@Lazy懒加载
@Lazy搭配@Component或@Bean使用,作用是延迟初始化 bean,告诉IOC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。
@Component
@Lazy
public class HelloWord {
@PostConstruct和@PreDestroy定制生命周期行为
@PostConstruct和@PreDestroy同样位于javax.annotation包下,也是来自JavaEE规范的两个Annotation,Spring直接借鉴了它们,用于定制Spring容器中Bean的生命周期行为。
它们都用于修饰方法,无须任何属性。
其中前者修饰的方法时Bean的初始化方法;而后者修饰的方法时Bean销毁之前的方法。
五:使用AOP
AOP(Aspect Orient Programming)也就是面向切面编程,作为面向对象编程的一种补充,已经成为一种比较成熟的编程方式。其实AOP问世的时间并不太长,AOP和OOP互为补充,面向切面编程将程序运行过程分解成各个切面。
AOP专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在JavaEE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。
配置开启AOP
!--启动@AspectJ支持--
aop:aspectj-autoproxy/
!--指定自动搜索Bean组件、自动搜索切面类--
context:component-scan base-package="cn.zyzpp"
context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/
/context:component-scan
@Aspect定义切面
@Aspect是不能被扫描到的,所以需要配合@Component注解。@Aspect标识自己是一个切面,将自己从自动代理中删除。
@Aspect
public class AspectModule {
}
@Pointcut定义切点
注意切点通过一个普通方法来定义,返回类型必须为void。支持execution表达式,within表达式,例如:
@Pointcut("execution(* cn.zyzpp.demo.*Word.*(..))")
private void businessService() {} // signature
第一个*表示任意返回类型,以.号进行划分,接下来是包名,类名,类名后是方法名,方法名跟括号,括号内是参数,两个点..意思是任意参数。
Advice增强处理
执行顺序
JoinPoint 获取目标方法
访问目标方法最简单的做法是定义增强处理方法时,将第一个参数定义为JoinPoint类型,当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点。JoinPoint里包含了如下几个常用的方法:
自定义注解向Advice传参
@Retention定义自定义注解的生命周期
@Target定义注解的作用位置
@Documented,@Inherited 忽略即可!
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Annota {
String value();
}
在目标方法使用此注解
@Annota("Mark")
public void say(String name){
....
}
完整AOP示例
@Component
@Aspect
public class MyAspect {
//声明切点
@Pointcut("execution(* cn.zyzpp.demo.*Word.*(..))")
public void pointcut(){}
//声明切点
@Pointcut("within(cn.zyzpp.demo.*)")
public void bizPointcut(){}
//前置通知:目标方法执行之前执行以下方法体的内容
@Before("pointcut()")
public void before(){
System.out.println(" before");
}
//前置通知:获取注解,给Advice传递参数
@Before("pointcut() && @annotation(annota)")
public void beforeWithAnnotaion(Annota annota) {
System.out.println("BeforeWithAnnotation: " + annota.value());
}
//前置通知:获取参数
@Before("pointcut()")
public void beforeArgs(JoinPoint joinPoint){
for (Object object:joinPoint.getArgs()){
System.out.println(" before args: "+object.toString());
}
}
//前置通知:获取对象
@Before("pointcut() && args(arg)")
public void beforeWithPar(Object arg){
System.out.println(" before obj: "+arg.toString());
}
//后置通知:目标方法执行之后执行以下方法体的内容,不管是否发生异常。
@After("pointcut()")
public void after() {
System.out.println(" After");
}
//返回通知::目标方法正常执行完毕时执行以下代码
@AfterReturning(pointcut="bizPointcut()" ,returning="retrunValue")
public void afterReturning(Object retrunValue){
System.out.println("AfterReturning: "+retrunValue);
}
//异常通知:目标方法发生异常的时候执行以下代码
@AfterThrowing(pointcut="pointcut()", throwing="e")
public void afterThrowing(RuntimeException e) {
System.out.println(" AfterThrowing: " + e.getMessage());
}
//环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码
@Around("pointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println(" Around: start");
Object obj = pjp.proceed();
System.out.println(" Around: end, return: "+obj);
return obj;
}
}
六、事物管理
一个数据库事务是一个被视为单一的工作单元的操作序列。这些操作应该要么完整地执行,要么完全不执行。事务管理是一个重要组成部分,RDBMS 面向企业应用程序,以确保数据完整性和一致性。事务的概念可以描述为具有以下四个关键属性说成是 ACID:
编程式 vs. 声明式
Spring 支持两种类型的事务管理:
声明式事务管理比编程式事务管理更可取,尽管它不如编程式事务管理灵活,但它允许你通过代码控制事务。
基于注解的方式
1.开启事务
!-- 初始化 数据源 --
bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
property name="driverClassName" value="com.mysql.jdbc.Driver" /
property name="url" value="jdbc:mysql://localhost:3306/TEST" /
property name="username" value="root" /
property name="password" value="123456" /
/bean
!-- 事务管理器配置 --
bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
property name="dataSource" ref="dataSource" /
/bean
!-- 使用annotation注解定义事务 --
tx:annotation-driven transaction-manager="transactionManager"/
2.service类@Transactional(name=value)
@Transactional参数
关注后端技术精选,每天推送优质好文