目录
IOC创建对象方式
IOC默认创建对象方式:使用无参构造方法,也可以使用构造器方法注入(有参构造)
有参构造里有三种方法:
- 索引注入
- 参数类型注入:基本数据类型直接写:int,引用数据类型写全路径:java.lang.String,如果存在多参数同类型,则不采用!
- 参数名注入:通过name和value来指定
在配置文件加载时,spring容器中托管的所有类就已经被初始化了
Spring配置
alias:别名
bean:配置javabean,其中id为唯一标识符,name为别名,用逗号或空格分号分隔,class指定托管类
import:用于团队开发,导入合并多个配置文件,会自动合并相同的配置
DI依赖注入
- 构造器注入
<bean id="hello" class="com.xiaopi3.pojo.Hello">
<constructor-arg name="name" value="pppp"/>
<constructor-arg name="age" value="1212"/>
</bean>
- set注入
<bean id="hello" class="com.xiaopi3.pojo.Hello">
<property name="name" value="pp"/>
<property name="age" value="12"/>
</bean>
- 其他
扩展注入:引入p空间和c空间。
- p空间:可以在标签属性上直接注入对象属性,对应set注入
- c空间:对应构造器注入,必须提供有参构造才行
<bean id="hello" class="com.xiaopi3.pojo.Hello" p:name="ppp" p:age="15"></bean>
注入方式有:xml配置和注解配置。可注入的类型:bean | ref | idref | list | set | map | props | value | null
bean作用域
singleton:单例
prototype:原型,每次获取bean都是新对象
request:request全局唯一
session:session全局唯一
application
websocket
bean xml自动装配
三种装配方式:xml、java、隐式,隐式方式为自动装配
在bean标签中:autowire="byName"
查找装配同该bean中set后名字匹配的配置bean。autowire="byType"
查找类型相同的进行装配。
<bean id="son" class="com.xiaopi3.Son" p:name="myson" p:age="1"></bean>
<bean id="dad" class="com.xiaopi3.Dad" autowire="byName"></bean>
而Dad中:
@Data
public class Dad {
private String name;
private int age;
private Son son;
}
bean 注解自动装配
使用注解需要满足2条件:
- 导入约束
多了一个context约束! - 启用注解
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
- 在java中需要注入的属性前加上注解即可
@Autowired
:会自动反射进行注入,不用再写set方法了,默认byType注入,多个匹配则按名称匹配
@Autowired(required = false)
:当前bean未找到时则不进行注入操作!
@Qualifier
:指定注入对象的名字,用来与@Autowired
搭配,byName
@Resource
:该注解是javax注解,作用差不多,组合,包含好几个功能,默认byName
,可以指定byType
,多个匹配按类型匹配
@Nullable
:加在参数上,标记该参数可以为null
注解使用
注解开发必须
- 导入AOP包
- 需要导入context约束
- 需要启动自动装配
- 需要启动包扫描:包扫描为了启用除了自动装配以外的注解!
例如:
@Component
:放在bean上,表示装配该bean
@Value
:注入值,放在属性上或set方法上
@Repository
:仓库,放在dao的类上,功能同@Component
@Service
:放在service层,功能同@Component
@Controller
:放在controller层,功能同@Component
@Scope
:作用域,放在bean上,限定范围
最佳实践:xml只用来管理bean,注解只用来完成属性的注入
Java类作为配置
使用java类来作为配置类,等价于xml配置文件:
// 配置
@Configuration
@ComponentScan(basePackages = "com.acme")
@Import(AppConfig2.class)
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
// 调用
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
注意:装配bean的两种方式:1.配置类里面加了@Bean;2.配置类配置了扫描包注解@ComponentScan
注意:@Import注解可以导入其他的配置类,相当于合并配置文件
AOP
代理模式
静态代理
优点:
使真实实体功能更纯粹、可以在代理类中增强一些其他功能、可以集中管理一些附加功能
缺点:
一个真实角色就产生一个代理角色,容易产生过多的代理角色,降低开发效率
动态代理
- 基于接口:jdk动态代理
- 基于类:cglib
- 基于字节码:javassist
优点:静态代理有的都有+代理的是一个接口,实用性更广
UserService userService = new UserServiceImpl();// 此处只要new一个实现了UserService的实现类即可动态改变生成的代理类
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);
UserService proxy = pih.getProxy();
proxy.add();
spring aop实现:xml配置
使用spring必须要导入一个织入的包:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
<scope>runtime</scope>
</dependency>
1. 切入点+通知:pointcut+advisor
这种方式功能强,可以获取被增强方法各种属性!!!
- 导入aop依赖包
- 编写增强类:依据增强类型实现不同的增强接口即可
//dao
public interface UserDao {
public void add();
public void delete();
}
//daoimpl
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("新增用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
}
//增强类
public class LogBefore implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"类,执行了该方法:"+method.getName());
}
}
- 配置xml
<bean id="userDao" class="com.xiaopi3.dao.UserDaoImpl"/>
<bean id="logBefore" class="com.xiaopi3.log.LogBefore"/>
<aop:config>
<aop:pointcut id="p1" expression="execution(* com.xiaopi3.dao.*.*(..))"/>
<aop:advisor advice-ref="logBefore" pointcut-ref="p1"/>
</aop:config>
- 获取需要注入的类,调用方法
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean("userDao", UserDao.class);
userDao.add();
userDao.delete();
}
2. 切入点+切面:pointcut+aspect
这种方式使用简单,功能简单!
- 导入aop包
- 编写切面类
public class LogAspect {
public void before(){
System.out.println("前置方法");
}
public void after(){
System.out.println("后置方法");
}
}
- 配置xml
<bean id="logAspect" class="com.xiaopi3.log.LogAspect"/>
<aop:config>
<aop:aspect ref="logAspect">
<aop:pointcut id="p1" expression="execution(* com.xiaopi3.dao.*.*(..))"/>
<aop:before method="before" pointcut-ref="p1"/>
<aop:after method="after" pointcut-ref="p1"/>
</aop:aspect>
</aop:config>
- 执行测试
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean("userDao", UserDao.class);
userDao.add();
userDao.delete();
}
3. 注解实现
注解实现需要导入aspctj包:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.6</version>
</dependency>
- 编写增强类
@Aspect
public class LogAspectAnnotation {
@Before("execution(* com.xiaopi3.dao.*.*(..))")
public void logBefore(){
System.out.println("log before====>>");
}
}
- 配置xml
需要开启环绕注解支持
<aop:aspectj-autoproxy/>
<bean id="userDao" class="com.xiaopi3.dao.UserDaoImpl"/>
<bean id="logAspect" class="com.xiaopi3.log.LogAspectAnnotation"/>
- 执行测试类
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean("userDao", UserDao.class);
userDao.add();
userDao.delete();
}
注意:代理配置中<aop:aspectj-autoproxy expose-proxy="false"/>
默认是false,如果选择true则使用cglib代理模式
事务
ACID原则:原子性、一致性、隔离性、持久性
spring支持两种事务:声明式和编程式,编程式由于侵入代码太多,不常采用。
使用aop配置事务
这里将所有mapper下的方法全部加入了事务
事务传播特性一共有六种:默认REQUIRED,表示支持事务,如果没有就新建。
PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。
整合
整合mybatis
导包:junit、mysql、spring-webmvc、mybatis、spring-jdbc、aspectjweave、mybatis-spring
1. mybatis单独回顾
- 编写实体类pojo
@Data
public class User {
public String name;
public int age;
}
- 编写实体类dao接口方法mapper类(等价于dao层的接口类)
public interface UserMapper {
public void insert(User user);
public List<User> select();
}
- 编写对应接口的配置文件xml,这里包括两个方法,插入和查询
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaopi3.mapper.UserMapper">
<select id="select" resultType="user">
select * from ooo.user;
</select>
<insert id="insert" parameterType="user">
insert into ooo.user (name,age) values(#{name},#{age});
</insert>
</mapper>
- 编写mybatis-config.xml核心配置文件,typeAliases用于定位pojo包,类似自动装配
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.xiaopi3.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ooo?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/xiaopi3/mapper/UserMapper.xml"/>
</mappers>
</configuration>
- 测试
注意:openSession中true表示启用事务自动提交
@Test
public void test01() throws IOException {
InputStream rin = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(rin);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = new User();
user1.setAge(13);
user1.setName("pp");
mapper.insert(user1);
List<User> select = mapper.select();
for (User user : select) {
System.out.println(user);
}
sqlSession.close();
问题一:找不到配置文件
将工程下pom下的配置新增如下,该配置表示对某个目录下的xml文件不过滤,进行输出。
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
2. mybatis整合
参考:mybatis.org
-
导包:junit、mysql、spring-webmvc、mybatis、spring-jdbc、aspectjweave、mybatis-spring
-
为了消除原先在测试类中的
SqlSessionFactory
和SqlSession
,使用spring来注入,需要配置这两个bean,分别对应:
SqlSessionFactory --> org.mybatis.spring.SqlSessionFactoryBean,该类需要数据源,所以在spring中配置数据源,mybatis中就不用配置了SqlSession --> org.mybatis.spring.SqlSessionTemplate
然后spring特有的,对接口的调用需要有个实现类,所以需要新加一个实现类!
<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/ooo?useSSL=false"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:com/xiaopi3/mapper/*.xml"/> <property name="dataSource" ref="dataSource"/> </bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> <bean id="userMapper" class="com.xiaopi3.mapper.UserMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean>
原来只需要
UserMapper.java
UserMapper.xml
,现在需要再加一个UserMapperImpl.java
实现类:实现类需要调用dao层数据,需要sqlSession的注入,注入必须要set方法public class UserMapperImpl implements UserMapper{ private SqlSession sqlSession; public void setSqlSession(SqlSession sqlSession) { this.sqlSession = sqlSession; } @Override public void insert(User user) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.insert(user); } @Override public List<User> select() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.select(); } }
注意:在spring配置文件中配置了的东西需要在mybatis中进行删除!删完后只留下这个(也可以全在spring中配置,将mybatis配置文件删掉)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="com.xiaopi3.pojo"/> </typeAliases> </configuration>
-
测试
@Test
public void test01() throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
User user1 = new User();
user1.setAge(13);
user1.setName("pp");
userMapper.insert(user1);
List<User> select = userMapper.select();
for (User user : select) {
System.out.println(user);
}
}
3. SqlSessionDaoSupport自动生成sqlSession
在MapperImpl类上继承该类,则可以直接使用getSession来获取sqlSession,同时配置文件中使用该类后可以舍弃掉SqlSessionTemplate类,直接注入SqlSessionFactory即可:
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
@Override
public void insert(User user) {
getSqlSession().getMapper(UserMapper.class).insert(user);
}
@Override
public List<User> select() {
return getSqlSession().getMapper(UserMapper.class).select();
}
}
配置文件中:
<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/ooo?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/xiaopi3/mapper/*.xml"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
<!-- <constructor-arg index="0" ref="sqlSessionFactory"/>-->
<!-- </bean>-->
<bean id="userMapper" class="com.xiaopi3.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
测试:同上不变
再加上事务处理
在MapperImpl中加入事务处理操作
- 在配置文件中配置好事务
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
">
<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/ooo?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/xiaopi3/mapper/*.xml"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
<!-- <constructor-arg index="0" ref="sqlSessionFactory"/>-->
<!-- </bean>-->
<bean id="userMapper" class="com.xiaopi3.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="p1" expression="execution(* com.xiaopi3.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="p1"/>
</aop:config>
</beans>
- mybatis配置文件配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.xiaopi3.pojo"/>
</typeAliases>
</configuration>
- Dao实现类,省略Dao接口和pojo类
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
@Override
public void insert(User user) {
getSqlSession().getMapper(UserMapper.class).insert(user);
System.out.println(1/0);// 此处肯定报错!
}
@Override
public List<User> select() {
return getSqlSession().getMapper(UserMapper.class).select();
}
}
- 测试类
@Test
public void test02() throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
User user1 = new User();
user1.setAge(18);
user1.setName("002");
userMapper.insert(user1);
List<User> select = userMapper.select();
for (User user : select) {
System.out.println(user);
}
}
结果由于insert方法报错,事务回滚了,虽然程序依旧报错,但是数据库数据没变化