Spring使用总结

一、装配Spring Bean(Spring IoC)

Bean的装配有两种方式,xml方式和注解方式,Bean主要分为自己开发的类和引入的第三方的包。
自己开发的类可以采用@Component注解的方式或者xml的方式装配,推荐使用@Component注解的方式,因为注解功能更为强大,既能实现XML的功能,也提供了自动装配的功能。
引入第三方的包可以采用@Bean注解的方式或者xml的方式装配,推荐使用xml的方式。

1、通过注解装配Bean

1.1、使用@Component装配Bean

定义POJO:

@Component(value = "role")
public class Role{
	@Value("1")
	private Long id;
	@Value("role_name_1")
	private String roleName;
	@Value("role_note_1")
	private String note;
}

注解@Component代表String IoC会把这个类扫描生成Bean实例,@Value代表值的注入。
定义一个Java Config类:

@ComponentScan
public class PojoConfig{
}

@ComponentScan代表进行扫描,默认是扫描当前包的路径。
@ComponentScan也可以指定扫描某些包或者某些类:

//扫描指定类
@ComponentScan(basePackageClasses = {Role.class, RoleServiceImpl.class})
//扫描指定包
@ComponentScan(basePackages = {"com.ssm.chapter10.annotation.pojo", "com.ssm.chapter10.annotation.service"}

从IoC容器中获取并使用注解装配完成的Bean:

ApplicationContext context = new AnnotationConfigApplicationContext("PojoConfig.class");
Role role = context.getBean(Role.class);
context.close();

1.2、自动装配——@Autowired
用@Autowired注解后,spring会自动寻找合适类型的bean注入进来。
@Autowired装配属性:

@Autowired
private Role role = null;

有时候IoC容器会寻找失败,然后抛出异常,如果这个属性可有可无,寻找失败也无妨,可以修改为:

@Autowired(required = false)
private Role role = null;

@Autowired注解也允许方法配置:

@Autowired
public void setRole(Role role){
	This.role = role;
}

@Autowired注解也允许带有参数的构造方法配置:

public RoleController2(@Autowired RoleService roleService){
	this.roleService = roleService;
}

1.3、自动装配的歧义性
但是,如果一个接口有多个实现类,IoC容器会不知道应该注入哪个实现类,为了消除这种歧义性,有两个注解可以办到:
@Primary——优先注入:

@Component("roleService3")
@Primary
public class RoleServiceImpl3 implements RoleService{
	......
}

@Primary代表如果存在多个RoleService接口的实现类,优先注入RoleServiceImpl3类的实例。
@Qualifier——按名称查找:

public class RoleController{
	@Autowired
	@Qualifier("roleService3")
	private RoleService roleService = null;
}

@Qualifier代表这个属性不按照类型的方式注入,而是按照名称查找,将名为roleService3的实现类注入。

1.4、使用@Bean装配Bean
@Bean可以注解到方法之上,并且将方法返回的对象作为Spring的Bean,存放在IoC容器中:

@Bean(name = "role")
public Role getRole(){
	return new Role;
}

2、通过XML配置装配Bean

2.1、装配简易值:
假设Source和JuiceMaker2都是已经创建好的类。

用xml装配:

<bean id="source" class="com.ssm.chapter9.pojo.Source">
	<property name="fruit" value="橙汁">
	<property name="sugar" value="">
	<property name="size" value="大杯">
</bean>
<bean id="juiceMaker2" class="com.ssm.chapter9.pojo.JuiceMaker2">
	<property name="beverageShop" value="贡茶">
	<property name="source" ref="source">
</bean>

2.2、装配集合:
先创建一个包含集合属性的类:

public class ComplexAssembly{
	private Long id;
	private List<String> list;
	private Map<String, String> map;
	private Properties props;
	private Set<String> set;
	private String[] array;
}

装配集合类:

<bean id="complexAssembly" class="com.ssm.chapter10.pojo.ComplexAssembly">
	<property name="id" value="1"/>
	<property name="list">
		<list>
			<value>value-list-1</value>
			<value>value-list-2</value>
			<value>value-list-3</value>
		</list>
	</property>
	<property name="map">
		<map>
			<entry key="key1" value="value-key-1"/>
			<entry key="key2" value="value-key-2"/>
			<entry key="key3" value="value-key-3"/>
		</map>
	</property>
	<property name="props">
		<props>
			<prop key="prop1">value-prop-1</prop>
			<prop key="prop2">value-prop-2</prop>
			<prop key="prop3">value-prop-3</prop>
		</props>
	</property>
	<property name="set">
		<set>
			<value>value-set-1</value>
			<value>value-set-2</value>
			<value>value-set-3</value>
		</set>
	</property>
	<property name="array">
		<array>
			<value>value-array-1</value>
			<value>value-array-2</value>
			<value>value-array-3</value>
		</array>
	</property>
</bean>

如果集合之中包含的不是String,而是类的话,则List、Set、Array修改为:

<list>
	<ref bean="role1"/>
	<ref bean="role2"/>
</list>

Map修改为:

<map>
	<entry key-ref="role1" value-ref="user1"/>
	<entry key-ref="role2" value-ref="user2"/>
</map>

其中role1和user1都是类。

从IoC容器中获取并使用xml装配完成的Bean:

ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
RoleService roleService = (RoleService)ctx.getBean("roleService");

3、加载属性文件

XML方式加载属性文件:

<beans ......>
	<context:property-placeholder ignore-resource-not-found="true" location="classpath:database-config.properties"/>
</beans>

这里的ignore-resource-not-found属性代表是否允许文件不存在,配置为true代表允许文件不存在,这里的location是一个配置属性文件路径的选项,可以配置一个或多个文件,多个文件用逗号分割,多个文件时也可以按如下方法进行配置:

<beans ......>
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<!-- 配置文件路径 -->
	<property name="locations">
		<array>
			<value>classpath:database-config.properties</value>
			<value>classpath:log4j.properties</value>
		</array>
	</property>
	<property name="ignoreResourceNotFound" value="true"/>
</beans>

4、条件化装配Bean

当属性文件配置不完全时,条件化装配可以阻止其装配,避免装配失败导致返回异常。
@Conditional:

@Conditional({DataSourceCondition.class})
public DataSource getDataSource(
@Value("${jdbc.database.driver}") String driver,
@Value("${jdbc.database.url}") String url,
@Value("${jdbc.database.username}") String username,
@Value("${jdbc.database.password}") String password){
}

这里通过@Conditional引入了一个类——DataSourceCondition,由它来判断属性文件是否配置完全:

public class DataSourceCondition implements Condition{
	@Override
	//获取上下文环境
	Environment env = context.getEnvironment();
	//判断是否存在关于数据库的基础配置
	return env.containsProperty("jdbc.database.driver")
		&& env.containsProperty("jdbc.database.url")
		&& env.containsProperty("jdbc.database.username")
		&& env.containsProperty("jdbc.database.password")
}

5、Bean的作用域

在默认的情况下,Spring IoC容器只会为配置的Bean生成一个实例,而不是多个,有时候我们会希望获得多个实例,这是由Spring的作用域所决定的。

Spring的4种作用域:

  1. 单例(singleton):它是默认选项,在整个应用中,Spring只为其生成一个Bean的实例。
  2. 原型(prototype):每次注入或者通过Spring Ioc容器获取Bean时,Spring都会为它创建一个新的实例。
  3. 会话(session):在Web应用中使用,就是在会话过程中Spring只创建一个实例。
  4. 请求(request):在Web应用中使用的,就是在一次请求中Spring会创建一个实例。

代码示例:

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class RoleDataSourceServiceImpl implements RoleDataSourceService{
}

6、Spring表达式(Spring EL)

二、面向切面编程(Spring AOP)

SpringAOP 是一种基于方法拦截的 AOP ,换句话说 Spring是一种只能支持方法拦截的 AOP。

Spring 中主要有两种方式去实现 AOP 拦截功能:

  • 使用@AspectJ 注解驱动切面
  • 使用 AspectJ 注入切面。

Spring AOP 的拦截方式中,真正常用的是用@AspectJ 注解的方式实现的切面,有时候 XML 配置也有一定的辅助作用。

1、使用@AspectJ注解开发 Spring AOP

1.1、选择切点
Spring 是方法级别的 AOP 框架,而我们主要也是以某个类的某个方法作为切点,用动态代理的理论来说,就是要拦截哪个方法织入对应的 AOP 通知。

创建接口:

public interface RoleService { 
	public void printRole(Role role) ;
}

创建接口的实现类:

@Component 
public class RoleServiceimpl implements RoleService { 
	@Override
	public void printRole (Role role) { 
		System.out.println("{id: " + role.getId() + "," + "role_name: " + role.getRoleName() + "note: " + role.getNote() + "}");

1.2、创建切面(拦截器)

定义切面:

@Aspect
public class RoleAspect{
	@Before("execution(*com.ssm.checpter11.aop.service.impl.RoleServiceImpl.printRole(..))")
	public void before(){
	}
	@After("execution(*com.ssm.checpter11.aop.service.impl.RoleServiceImpl.printRole(..))")
	public void after(){
	}
	@AfterReturning("execution(*com.ssm.checpter11.aop.service.impl.RoleServiceImpl.printRole(..))")
	public void afterReturning(){
	}
	@AfterThrowing("execution(*com.ssm.checpter11.aop.service.impl.RoleServiceImpl.printRole(..))")
	public void afterThrowing(){
	}
	@Around("execution(*com.ssm.checpter11.aop.service.impl.RoleServiceImpl.printRole(..))")
	public void around(ProceedingJoinPoint jp){
		try{
			jp.proceed();
			//先调度前置通知,接着反射切点方法,然后调度后置通知和返回通知
		}catch(Throwable e){
			e.printStackTrace();
		}
	}
}

在Spring中只要通过@Aspect注解一个类,那么Spring IoC容器就会认为这是一个切面了。

切面通过execution语句来确定要拦截的方法:

@Before("execution(*com.ssm.checpter11.aop.service.impl.RoleServiceImpl.printRole(..))")

该正则表达式要在一个拦截器中书写多次,比较麻烦,可以使用@Pointcut解决:

@Aspect
public class RoleAspect{
	@Pointcut("execution(*com.ssm.checpter11.aop.service.impl.RoleServiceImpl.printRole(..))")
	public void print(){
	}
	@Before("point()")
	public void before(){
	}
	@After("point()")
	public void after(){
	}
	@AfterReturning("point()")
	public void afterReturning(){
	}
	@AfterThrowing("point()")
	public void afterThrowing(){
	}
	@Around("point()")
	public void around(ProceedingJoinPoint jp){
		try{
			jp.proceed();
			//先调度前置通知,接着反射切点方法,然后调度后置通知和返回通知
		}catch(Throwable e){
			e.printStackTrace();
		}
	}
}

如果需要给通知传递参数,execution语句可以修改为:

@Before("execution(*com.ssm.checpter11.aop.service.impl.RoleServiceImpl.printRole(..)) " + "&& args(role, sort)")
public void before(Role role, int sort){
}

1.3、生成动态代理类

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.ssm.chapter11.aop")
public class AopConfig(){
	@Bean
	public RoleAspect getRoleAspect(){
		return new RoleAspect();
	}
}

@EnableAspectJAutoProxy代表启用AspectJ框架的自动代理,@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的,作用为:配置spring容器(应用上下文)。

1.4、测试AOP流程

ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);
RoleService roleService = (RoleService)ctx.getBean(RoleService.class);
Role role = new Role();
roleService.printRole(role);

2、引入(对已有类进行增强,在已有类中引入新的接口)

2.1、定义新的接口

public interface RoleVerifier{
	public boolean verify(Role role);
}

2.2、定义接口的实现类

public class RoleVerifierImpl implements RoleVerifier{
	@Override
	public boolean verify(Role role){
		return role != null;
	}
}

2.3、加入接口到切面类中

@DeclareParents(value="com.ssm.chapter11.aop.service.impl.RoleServiceImpl+", defaultImpl = RoleVerifierImpl.class)
public RoleVerifier roleVerifier;

该语句的含义是对RoleServiceImpl类进行增强,在RoleServiceImpl类中引入一个新的接口,而RoleVerifierImpl就是引入的新接口的实现类。

2.4、使用引入的加强功能

ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);
RoleService roleService = ctx.getBean(RoleService.class);
RoleVerifier roleVerifier = (RoleVerifier)roleService;
Role role = new Role();
if(roleVerifier.verify(role)){
	roleService.printRole(role);
}

3、多个切面

当一个切点有多个切面时,默认情况下这些切面的执行没有任何顺序,不过我们可以通过给这些切面添加注解@Order()来确定顺序,示例如下:

@Aspect
@Order(1)
public class Aspect1{
	...... 
}

三、MyBatis-Spring结合

1、简单应用

1.1、配置MyBatis

1.1.1、配置MyBatis配置文件

<configuration>
	<settings>
		...
	</settings>
	<typeAliases>
		...
	</typeAliases>
	<mappers>
		...
	</mappers>
</configuration>

1.1.2、配置映射器

定义一个POJO:

public class Role{
	private Long id;
	private String roleName;
	private String note;
}

定义映射器接口:

@Repository
public interface RoleMapper{
	public Role getRole(Long id);
}

定义xml文件:

<mapper namespace="com.learn.ssm.chapter3.mapper.RoleMapper">
	<select id="getRole" parameterType="long" resultType="role">
		select id, role_name as roleName, note from t_role where id = #{id}
	</select>
</mapper>

1.2、配置Spring
1.2.1、配置dataSource

<!--数据库连接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
	<property name="username" value="root" />
	<property name="password" value="123456" />
	<property name="driverClass" value="com.mysql.jdbc.Driver" />
	<property name="url" value="jdbc:mysql://localhost:3306/chapter12" />
</bean>

1.2.2、配置SqlSessionFactoryBean

<!--集成MyBatis-->
<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />
	<!--指定MyBatis配置文件-->
	<property name="configLocation" value="classpath:sqlMapConfig.xml" />
</bean>

1.2.3、配置扫描方式加载映射器

<!--采用自动扫描方式创建mapper bean-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<!--设置要扫描的包-->
	<property name="basePackage" value="com.ssm.chapter12.mapper" />
	<property name="SqlSessionFactoryBeanName" value="SqlSessionFactory" />
	<!--指定标注才扫描成为Mapper-->
	<property name="annotationClass" value="org.springframework.stereotype.Repository" />
</bean>

这样配置以后Spring IoC容器将把包名为"com.ssm.chapter12.mapper",注解为@Repository的接口扫描为映射器对象。

1.3、使用

ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
RoleMapper roleMapper = ctx.getBean(RoleMapper.class);
roleMapper.getRole(1);

2、数据库事务管理

2.1、MyBatis配置

在简单应用的基础上继续添加下列配置。

2.1.1、启用扫描机制,并指定扫描对应的包

<context:annotation-config />
<context:component-scan base-package="com.ssm.chapter13.*">

2.1.2、事务管理器配置数据源事务

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource" />
</bean>

2.1.3、使用注解定义事务

<tx:annotation-driven transaction-manager="transactionManager" />

2.2、配置服务类
2.2.1、定义接口

public interface RoleService{
	public int insertRole(Role role);
}
public interface RoleListService{
	public int insertRoleList(List<Role> roleList);
}

2.2.2、创建接口的实现类

@Service
public class RoleServiceImpl implements RoleService{
	@Autowired
	private RoleMapper roleMapper = null;
	
	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED)
	public int insertRole(Role role){
		return roleMapper.insertRole(role);
	}
}
@Service
public class RoleListServiceImpl implements RoleListService{
	@Autowired
	private RoleService roleService = null;
	
	@Override
	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
	public int insertRoleList(List<Role> roleList){
		int count = 0;
		for(Role role : roleList){
			count += roleService.insertRole(role);
		}
		return count;
	}
}

@Service写在类的上面,标注将这个类交给Spring容器管理,spring容器要为他创建对象。
@Transactional注解,表示该服务类实现方法将会在对应的隔离级别和传播行为中运行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值