简单总结一下使用的spring
1.”hello world”
使用springmvc的好处是
降低组件之间的耦合度,实现软件各层之间的解耦,
ioc与di(依赖注入):包含并管理应用对象的配置声明周期,你可以配置你的每个bean如何被创建,也可以配置每个bean是只有一个实例,还是每次需要时都生成一个新的实例,以及它们是如何相互关联的,
aop(面向切面):采用了面向切面编程来实现很多基础但是与业务逻辑无关的功能的解耦。比如:事务管理、日志、权限验证
实例化spring容器
方法一:
在类路径下寻找配置文件来实例化容器
ApplicationContext ctx=new ClassPathXmlApplicationContext(new String[]{“beans.xml”});
可以在整个类路径中寻找xml文件
1.通过这种方式加载。需要将spring的配置文件放到当前项目的classpath路径下
2.classpath路径指的是当前项目的src目录,该目录是java源文件的存放位置
ps:ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/a_hello/applicationContext.xml");
方法二:
在文件系统路径下寻找配置文件来实例化容器
ApplicationContext ctx=new FileSystemXmlApplication(new String[]{“d:\\beans.xml”});
Spring的配置文件可以指定多个,可以通过string数组传入。
从spring容器中得到bean
当spring容器启动后,因为spring容器可以管理bean对象的创建,销毁等生命周期,所以我们只需要从容器直接获取bean对象就行,而不用编写一句代码来创建bean对象。从容器获取bean对象的代码如下:
ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
Gril gril=(Gril)ctx.getBean("gril");
//销毁容器对象
ac.destory();`
加载各种路径下spring.xml文件
// 测试ClassPathResource
@Test
public void testClassPathResource() throws Exception {
Resource resource1 = new ClassPathResource("cn/itcast/spring/c_resource/applicationContext_dao.xml");
Resource resource2 = new ClassPathResource("applicationContext_dao.xml", this.getClass());
System.out.println(resource1.getFile().getAbsolutePath());
System.out.println(resource2.getFile().getAbsolutePath());
}
// FileSystemResource
// UrlResource
@Test
public void test2() throws Exception {
Resource resource = new FileSystemResource("c:/applicationContext.xml");
System.out.println(resource.exists());
System.out.println(resource.getFile().getAbsolutePath());
System.out.println("\n");
Resource resource2 = new UrlResource("file://c:/applicationContext.xml");
System.out.println(resource2.exists());
System.out.println(resource.getFile().getAbsolutePath());
}
// ServletContextResource,需要在Web环境下才可以
@Test
public void testServletContextResource() {
// Resource resource = new ServletContextResource(servletContext, "/WEB-INF/classes/applicationContext.xml");
// System.out.println(resource);
}
2.bean的创建与销毁
方法一:无参构造方法的创建bean对象
public class Gril{
....
其内部的字段需要生成get与set方法
同时需要有无参的构造方法
}
spring.xml中配置
<bean id="gril" class="com.zhengzhigu.Gril">
<property name="id" value="201501"/>
<property name="name" value="老张"/>
</bean>
ps:SpringContext利用无参的构造函数创建一个对象,然后利用setter方法赋值。所以如果无参构造函数不存在,Spring上下文创建对象的时候便会报错。
方法二:利用有参的构造方法
public class Person{
public Person(String name,Integer id){
....
}
}
spring.xml中
<bean class="com.mc.base.learn.spring.bean.Person" id="person">
<constructor-arg name="id" value="2015217"></constructor-arg>
<constructor-arg name="name" value="zhengzhigu"></constructor-arg>
</bean>
方法三:使用静态工厂方法实例化
public class UserDao{
.....
}
public class DaoFactory{
public static UserDai getUserDaoByStaticFactoryMethod(){
return new UserDao();
}
}
<!--静态工厂方法实例化-->
<bean id="userDao" class="com.gudai.DaoFactory" factory-method="getUserDaoByStaticFactoryMethod"/>
方法四:实例工厂方法实例化
public class UserDao{
...
}
public class DaoFactory{
public DaoFactory(){
System.out.println("DaoFactory创建");
public UserDao getUserDaoByFactoryMethod(){
return new UserDao();
}
}
}
spring.xml配置
<bean id="daoFactory" class="com.gudai.DaoFactory"/>
<bean id="userDao" factory-bean="daoFactory" factory-method="getUserDaoByFactoryMethod"/>
注意:bean的销毁是在web应用结束后被销毁的,如果你想在bean的创建之前或之后使用一些方法可以有如下方法
第一种:通过@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作
第二种是:通过 在xml中定义init-method 和 destory-method方法
第三种是: 通过bean实现InitializingBean和 DisposableBean接口
直接上xml中配置文件:
<bean id="personService" class="com.myapp.core.beanscope.PersonService" scope="singleton" init-method="init" destroy-method="cleanUp">
</bean>
@PostConstruct和 @PreDestroy注解在bean中方法名上即可在初始化或销毁bean之前执行。
bean的作用域默认是singleton(默认),即在每个spring ioc 容器中一个bean定义只有一个对象实例(共享)
可以配置成多例的允许bean被多次实例化
<!--
在默认情况下,spring创建bean是单例模式
scope
singleton 默认
单例
属性是共享的
一般情况下,把数据存放在方法中的变量中
prototype
多例
当一个bean是多例模式的情况下,lazy-init为false或者true
-->
<bean id="helloWorld" class="com.gudai.HelloWorld" scope="prototype" lazy-init="false"></bean>
bean的继承的方式如下
关于继承
1,如果不想让配置文件中的bean创建对象,则把bean的abstract属性设为true即可
2,如果想让一个子类拥有父类的属性,则需要指定bean的parent属性
<!-- abstract:告诉spring容器,该类不能创建对象 -->
<bean id="baseDao" class="com.gudai.BaseDao" abstract="true">
<property name="s" value="aaa"></property>
</bean>
<bean id="userDao" class="com.gudai.UserDao" parent="baseDao"></bean>
自动装配(将数据封装到bean中)
如果是单个设置多个属性装配,会很麻烦的生成bean;
<!-- ###############自动装配############### -->
<bean id="userDao" class="com.gudai.d_auto.UserDao"></bean>
<bean id="userService" class="com.gudai.d_auto.UserService"></bean>
<!-- 如果根据类型自动装配: 必须确保IOC容器中只有一个该类型的对象 -->
<bean id="userAction" class="com.gudai.d_auto.UserAction"></bean>
<!-- 报错: 因为上面已经有一个该类型的对象,且使用了根据类型自动装配
<bean id="userService_test" class="com.gudai.d_auto.UserService" autowire="byType"></bean>
-->
1.根据名称自动装配(byName)。因为spring 容器中Bean的名称是唯一的,所以不会产生歧义,推荐使用这种方式。
2.根据类型自动装配(byType)。在Spring容器中可能会找到多个跟需要注入的bean的类型相同的Bean,所以会产生歧义,Spring容器不知道注入哪个Bean,这时会抛出异常。
3.根据构造器自动装配(constructor)。这种方式比较复杂,不做分析。
ps:全局装配default-autowire="byName"> 根据名称自动装配(全局)
手工装配各种数据类型的数据
1.装配普通数据
<property name="id" value="2015"/>
2.引入其它bean
<property name="customer" ref="customer"/>
3.装配集合(list与数组)
<property name="tels">
<list>
<value>135</value>
<value>136</value>
</list>
</property>
4.装配集合(set)
<property name="orderSet" class="com.gudai.Customer">
<set>
<ref bean="order1"/>
<ref bean="order2"/>
</set>
</property>
5.装配map
<property name="telAddressMap">
<entry key="135">
<value>安徽</value>
</entry>
</property>
ps:得到bean
1.得到bean需要强转
DeptService deptService = (DeptService) ac.getBean("deptService");
//3.1 从容器中获取指定名称的bean对象
//DeptDao deptDao = (DeptDao) ac.getBean("deptDao");
//3.2 根据类型从容器获取实例 【改类型只能在IOC中有唯一的对象,否则报错】
//DeptDao deptDao = ac.getBean(DeptDao.class);
//3.3 泛型,不需要强转
//DeptDao deptDao = ac.getBean("deptDap", DeptDao.class);
//3.4 获取容器中bean对象的数量
//int count = ac.getBeanDefinitionCount();
3.各个注解
通过注解的方式,把对象加入ioc容器。
创建对象以及处理对象依赖关系,相关的注解:
@component 指定把一个对象加入ioc容器
@Repository 作用同@component;在持久层使用
@Service 作用同@component;在业务逻辑层使用
@Controller 作用同@component;在控制层使用
@Resource 属性注入按名称注入,@Autowired按类型注入
@Scope(“prototype”)
4.各种配置
对properties文件的加载方式
方式一:(加载classpath下properties文件)
//读取配置文件
String resource="jdbc.properties";
InputStream inputStream=getClass().getResourceAsStream(resource);
Properties props=new Properties();
props.load(inputStream);
// 并初始化信息
jdbcUrl = props.getProperty("jdbcUrl");
driverClass = props.getProperty("driverClass");
username = props.getProperty("username");
password = props.getProperty("password");
方法二:
<!-- 加载外部的properties文件(方式一),用于解析${}形式的变量。
如果需要加载多个properties文件,就写在一起,之间使用逗号隔开。
<context:property-placeholder location="classpath:com/gudai/spring/k_placeholder/jdbc.properties"/>
-->
方法三:
<!-- 加载外部的properties文件(方式二)
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/gudai/spring/k_placeholder/jdbc.properties</value>
</list>
</property>
</bean>
-->
5.事务之aop
事务
xml方式配置
jdbc与hibernate可以实现细粒度的事务管理
spring提供了对事物的管理,其核心就是基于aop,提供的是粗粒度的事务控制:只能给整个方法应用事务,不可以对方法的某几行应用事务(因为aop拦截的是方法)
spring声明式事务管理器类
jdbc技术:DataSourceTransactionManager;
Hibernate技术:HibernateTransactionManager
xml方式配置事务
<!-- #############5. Spring声明式事务管理配置############### -->
<!-- 5.1 配置事务管理器类 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 5.2 配置事务增强(如果管理事务?)
<!-- ==== 基于XML的方式配置事务 ==== -->
<!-- 声明“通知”:
对于以get或find开头的方法,使用只读的事务,其他的方法都使用正常的事务
read-only:表示事务是否是只读的,默认为false。-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*" read-only="false"/>
</tx:attributes>
</tx:advice>
<!-- 5.3 Aop配置: 拦截哪些方法(切入点表表达式) + 应用上面的事务增强配置 -->
<aop:config>
<aop:pointcut expression="execution(* com.gudai.a_tx.DeptService.*())" id="pt"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>
注解的方式配置事务
实现的步骤是
必须引入aop相关的jar文件,bean.xml中指定注解方式实现声明式事务管理以及应用的事务管理器类,在需要添加事务控制的地方,写上:@Transactional
@Transactional注解
1.应用事务的注解
2.定义到方法上:当前方法应用spring的声明式事务
3.定义到类上:当前类的所有的方法都应用spring声明事务管理
4.定义到父类上:当执行父类的方法时候应用事务
<!-- 事务管理器类 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.gudai.b_anno"></context:component-scan>
<!-- 注解方式实现事务: 指定注解方式实现事务 -->
<tx:annotation-driven transaction-manager="txManager"/>
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 1. 数据源对象: C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///hib_demo"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
<property name="initialPoolSize" value="3"></property>
<property name="maxPoolSize" value="10"></property>
<property name="maxStatements" value="100"></property>
<property name="acquireIncrement" value="2"></property>
</bean>
<!-- 2. JdbcTemplate工具类实例 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务管理器类 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.gudai.b_anno"></context:component-scan>
<!-- 注解方式实现事务: 指定注解方式实现事务 -->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
public class DeptService {
@Resource
private DeptDao deptDao;
/*
* 事务控制?
*/
@Transactional
public void save(Dept dept){
deptDao.save(dept);
int i = 1/0;
deptDao.save(dept);
}
}
事务的属性
@Transactional(
readOnly = false, // 读写事务
timeout = -1, // 事务的超时时间不限制
noRollbackFor = ArithmeticException.class, // 遇到数学异常不回滚
isolation = Isolation.DEFAULT, // 事务的隔离级别,数据库的默认
propagation = Propagation.REQUIRED // 事务的传播行为
)
public void save(Dept dept){
deptDao.save(dept);
int i = 1/0;
deptDao.save(dept);
}
aop面向切面编程是
切面:抽取的大量需要重复执行的代码
切入点:需要加入切面的方法
xml方式aop
<!-- 切面类 -->
<bean id="aop" class="com.gudai.f_aop_xml.Aop"></bean>
<!-- Aop配置 -->
<aop:config>
<!-- 定义一个切入点表达式: 拦截哪些方法 -->
<aop:pointcut expression="execution(* com.gudai.f_aop_xml.*.*(..))" id="pt"/>
<!-- 切面 -->
<aop:aspect ref="aop">
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pt"/>
<!-- 前置通知: 在目标方法调用前执行 -->
<aop:before method="begin" pointcut-ref="pt"/>
<!-- 后置通知: -->
<aop:after method="after" pointcut-ref="pt"/>
<!-- 返回后通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
注解方式
@Component
@Aspect // 指定当前类为切面类
public class Aop {
// 指定切入点表单式: 拦截哪些方法; 即为哪些类生成代理对象
@Pointcut("execution(* com.gudai.e_aop_anno.*.*(..))")
public void pointCut_(){
}
// 前置通知 : 在执行目标方法之前执行
@Before("pointCut_()")
public void begin(){
System.out.println("开始事务/异常");
}
// 后置/最终通知:在执行目标方法之后执行 【无论是否出现异常最终都会执行】
@After("pointCut_()")
public void after(){
System.out.println("提交事务/关闭");
}
// 返回后通知: 在调用目标方法结束后执行 【出现异常不执行】
@AfterReturning("pointCut_()")
public void afterReturning() {
System.out.println("afterReturning()");
}
// 异常通知: 当目标方法执行异常时候执行此关注点代码
@AfterThrowing("pointCut_()")
public void afterThrowing(){
System.out.println("afterThrowing()");
}
// 环绕通知:环绕目标方式执行
@Around("pointCut_()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕前....");
pjp.proceed(); // 执行目标方法
System.out.println("环绕后....");
}
Spring.xml
中配置
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.gudai.e_aop_anno"></context:component-scan>
<!-- 开启aop注解方式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
6.spring整合
spring与hibernate(同时可以整合spring jdbc)
<!-- 数据源配置 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///TeachSystem"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
<property name="initialPoolSize" value="5"></property>
<property name="maxPoolSize" value="10"></property>
<property name="maxStatements" value="100"></property>
<property name="acquireIncrement" value="3"></property>
</bean>
<!-- 将连接池交给spring管理 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 使用jdbcTemplate工具类实例 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
spring与mybatis整合
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 数据源, -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="initialPoolSize" value="5"></property>
<property name="maxPoolSize" value="10"></property>
<property name="maxStatements" value="100"></property>
<property name="acquireIncrement" value="3"></property>
</bean>
<!-- sqlSessinFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 加载mybatis的配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"/>
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
spring与spring jdbc整合
<!-- 2. JdbcTemplate工具类实例 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 3. dao实例 -->
<bean id="deptDao" class="com.gudai.a_tx.DeptDao">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!-- 4. service实例 -->
<bean id="deptService" class="com.gudai.a_tx.DeptService">
<property name="deptDao" ref="deptDao"></property>
</bean>
ps:spring jdbc的crud
添加
String sql = "insert into t_user(name, age) values (?, ?)";
jdbcTemplate.update(sql, new Object[] { user.getName(), user.getAge() });
删除
String sql = "delete from t_user where id=?";
jdbcTemplate.update(sql, new Object[] { id });
更新
String sql = "update t_user set name=?, age=? where id=?";
jdbcTemplate.update(sql, new Object[] { user.getName(), user.getAge(), user.getId() });
查询
根据id查询一个数据
String sql = "select name,age from t_user where id=?";
return (User) jdbcTemplate.queryForObject(sql, new Object[] { id }, new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
String name = rs.getString(1);
int age = rs.getInt(2);
return new User(id, name, age);
}
});
查询所有
String sql = "select id,name,age from t_user";
return jdbcTemplate.query(sql, new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
int id = rs.getInt(1);
String name = rs.getString(2);
int age = rs.getInt(3);
return new User(id, name, age);
}
});
查询分页
int count = jdbcTemplate.queryForInt("select count(*) from t_user");
List list = jdbcTemplate.query(//
"select id,name,age from t_user limit ?,?", //
new Object[] { 0, 10 }, //
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
int id = rs.getInt(1);
String name = rs.getString(2);
int age = rs.getInt(3);
return new User(id, name, age);
}
});
ps:当然可以封装数据是
String sql = "select * from t_dept";
List<Dept> list = jdbcTemplate.query(sql, new MyResult());
return list;
}
class MyResult implements RowMapper<Dept>{
// 如何封装一行记录
@Override
public Dept mapRow(ResultSet rs, int index) throws SQLException {
Dept dept = new Dept();
dept.setDeptId(rs.getInt("deptId"));
dept.setDeptName(rs.getString("deptName"));
return dept;
}
}
ps:spring的注解扫描
<!-- 开启注解扫描 -->
<context:component-scan base-package="cn.gudai"></context:component-scan>