Spring学习笔记
核心: IOC AOP
基本配置文件:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
IOC
ioc 的作用: 解耦
IOC 解决的问题:
依赖注入(DI)是实现 IOC 的一种方法。
- 如果一个类A 的功能实现需要借助于类B,那么就称类B是类A的依赖,如果在类A的内部去实例化类B,那么两者之间会出现较高的耦合,一旦类B出现了问题,类A也需要进行改造,如果这样的情况较多,每个类之间都有很多依赖,那么就会出现牵一发而动全身的情况,程序会极难维护,并且很容易出现问题。
- 假如现在有N多个类,需要用到Class B,那就需要在类里面实例化N多次,这样对于后期的维护和管理都是不方便的,如果后期需求发生改变,那更改量有大很多。
IOC创建对象的方式
默认使用对象的无参构造方法创建对象, 当对象没有无参构造的时候会出现异常, 此时需要指定使用带参数的构造方法。
默认使用无参构造:
<bean id="user" class="com.xtyuns.pojo.User">
<property name="name" value="Spring"/>
</bean>
使用有参构造(使用name方法):
<bean id="user" class="com.xtyuns.pojo.User">
<constructor-arg name="name" value="Spring"/>
</bean>
有参构造还有两种不常用的方法: index(参数索引), type(参数类型)
总结
- 在配置加载的时候, 容器管理的对象就已经初始化加载了。
配置
-
bean 标签
<bean id="user" class="com.xtyuns.pojo.User" name="u"> <constructor-arg name="name" value="Spring"/> </bean> <!-- id: 对象名 class: 类的全限定名 name: 对象的别名, 相当于 alias 标签, 但是更强大: 可以设置多个别名 -->
-
import 标签
<import resource="beans2.xml"/> <!-- 作用: 引入其他的 bean.xml 文件, 可以将所有的bean汇总到同一个xml中 -->
Bean的注入方法
package com.xtyuns.pojo;
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
package com.xtyuns.pojo;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class Student {
String name;
User teacher;
String[] games;
List<String> books;
Set<String> hobbys;
Map<String, String> card;
Properties info;
public Student() {
}
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User getTeacher() {
return teacher;
}
public void setTeacher(User teacher) {
this.teacher = teacher;
}
public String[] getGames() {
return games;
}
public void setGames(String[] games) {
this.games = games;
}
public List<String> getBooks() {
return books;
}
public void setBooks(List<String> books) {
this.books = books;
}
public Set<String> getHobbys() {
return hobbys;
}
public void setHobbys(Set<String> hobbys) {
this.hobbys = hobbys;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
}
基于构造函数的依赖注入
默认构造
<bean id="u1" class="com.xtyuns.pojo.User">
<property name="name" value="Spring"/>
</bean>
带参构造
<bean id="stu" class="com.xtyuns.pojo.Student">
<constructor-arg name="name" value="xtyuns"/>
</bean>
基于setter方法的依赖注入
对象引用
<bean id="stu" class="com.xtyuns.pojo.Student">
<property name="teacher" ref="u1"/>
</bean>
数组注入
<bean id="stu" class="com.xtyuns.pojo.Student">
<property name="games">
<array>
<value>英雄联盟</value>
<value>王者荣耀</value>
<value>守望先锋</value>
<value>刺激战场</value>
</array>
</property>
</bean>
List 注入
<bean id="stu" class="com.xtyuns.pojo.Student">
<property name="books">
<list>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
<value>三国演义</value>
</list>
</property>
</bean>
Map 注入
<bean id="stu" class="com.xtyuns.pojo.Student">
<property name="card">
<map>
<entry key="编号" value="18001"/>
</map>
</property>
</bean>
Set 注入
<bean id="stu" class="com.xtyuns.pojo.Student">
<property name="hobbys">
<set>
<value>吃饭</value>
<value>睡觉</value>
<value>看电影</value>
</set>
</property>
</bean>
Properties 注入
<bean id="stu" class="com.xtyuns.pojo.Student">
<property name="info">
<props>
<prop key="学号">18001</prop>
</props>
</property>
</bean>
其他注入
p命名空间
xmlns:p="http://www.springframework.org/schema/p"
c命名空间
xmlns:c="http://www.springframework.org/schema/c"
自动装配
<bean autowire="byName" id="people" class=""
<!-- 会自动在Spring上下文中查找setxxx() 方法所对应的beanid, 并进行自动装配 -->
<bean autowire="byType" id="people" class=""
<!-- 会自动在Spring上下文中查找setxxx() 方法所对应Bean的类型, 并进行自动装配 -->
byName 依赖 id 进行注入
byType 依赖 class 进行注入
常用的是使用注解进行自定装配Bean, 详见: 注解开发
注解开发
Spring4 之后使用注解开发需要导入
Spring-aop
的jar包, 并导入context
约束
-
首先指定注解扫描包的路径
<context:component-scan base-package="com.xtyuns"/> <!-- 当使用 <context:component-scan/> 后, 就可以将 <context:annotation-config/> 省略了 -->
-
在相应的Bean上使用注解即可
Spring JavaConfig
@Configuration
定义配置类, 替换xml配置文件
@ComponentScan("com.xtyuns")
定义注解扫描包路径
@Import(Config.class)
引入另一个配置类
@ImportResource("")
引入xml配置类
@Bean("name")
定义一个Bean, 相当于<Bean id="name"...(使用注解定义的Bean开启扫描即可, 无须再次定义Bean)
定义Bean的注解
@Conponent
@Conponent("Bean的名称")
定义Bean, 不好归类时使用
@Repository
@Repository("Bean的名称")
定义DAO层Bean
@Service
@Service("Bean的名称")
定义业务层Bean
@Controller
@Controller("Bean的名称")
定义控制层Bean
自动装配Bean
@Autowired
@Autowired(required=false)
忽略当前要注入的Bean, 如果有直接注入, 没有则跳过, 不会报错
@Qualifier
按名称装配Bean, 与@Autowired组合使用, 解决按类型匹配找到多个Bean问题
@Resource(name="xxx", type="xxx")
默认按名称装配, 当找不到名称匹配的Bean再按类型装配, 也可以通过参数显式指定装配方式
Autowired 默认使用 byType的方式进行注入, 当存在多个相同Type的时候, 会使用变量名进行byName注入, 或者使用@Qualifier注解来通过byName的方式指明使用哪一个实现类
定义Bean的作用域和生命过程
@Scope("prototype")
值有:singleton, prototype, session, request, session, globalSession
@PostConstruct
相当于init-method, 使用在方法上, 当Bean初始化时执行
@PreDestroy
相当于destory-method, 使用在方法上, 当Bean销毁时执行
声明式事务
@Transactional
AOP
AOP 的底层是代理模式
需要导包: aspectjweaver
AOP的名词结束
-
Advice (通知/增强)
要增强的代码/功能, 如日志功能
-
Joinpoint (连接点)
spring允许使用通知的地方 (@Before, @After, @AfterRunning, @AfterThrowing, @Around)
-
Pointcut (切入点)
进行注入Advice 的位置, 而连接点是允许注入的位置
-
Aspect (切面)
切入点+通知 = 切面
-
Target (目标对象)
被代理对象
-
Weaving (织入)
将通知应用到连接点的过程
-
Proxy (代理)
生成的代理对象
AOP Demo
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="user" class="com.xtyuns.service.UserServiceImpl"/>
<bean id="beforeLog" class="com.xtyuns.log.BeforeLog"/>
<bean id="timeLog" class="com.xtyuns.log.TimeLog"/>
<aop:config>
<aop:pointcut id="cutp" expression="execution(* com.xtyuns.service.UserService+.*(..))"/>
<!-- 方式一: 通过定义通知器来实现aop -->
<aop:advisor advice-ref="beforeLog" pointcut-ref="cutp"/>
<!-- 方式二: 通过定义切面来实现aop, ref设置Advice(通知) Bean -->
<aop:aspect ref="timeLog">
<aop:around method="around" pointcut-ref="cutp"/>
<aop:before method="before" pointcut-ref="cutp"/>
<aop:after method="after" pointcut-ref="cutp"/>
</aop:aspect>
</aop:config>
</beans>
AOP注解
-
开启aop注解
<aop:aspectj-autoproxy/>
-
使用aop注解
@Aspect @Before(execution表达式) @After, @AfterRunning, @AfterThrowing, @Around
Spring整合Mybatis
基本步骤
-
编写Dao接口, 以及相应的Mapper.xml
需要导入 mybatis
同时注意配置maven的build标签, 解决xml无法打包的问题
-
使用spring-jdbc配置数据源(DataSource)
需要导入 spring-jdbc
-
声明dataSource对象和sqlSessionFactory对象
需要导入 mysql-connector-java, mybatis-spring
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 这里相当于接替了mybatis-config.xml --> <property name="dataSource" ref="dataSource"/> <!-- 因为com.xtyuns.dao包中UserDao和UserDao.xml同名, 所以要使用classpath*: --> <property name="mapperLocations" value="classpath*:com/xtyuns/dao/*.xml"/> </bean>
-
声明sqlSessionTemplate对象
<!-- 相当于Mybatis中的sqlSession对象 --> <bean id="sessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg ref="sqlSessionFactory"/> </bean>
-
编写测试类并运行测试
@Test public void getUserList() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); SqlSessionTemplate sqlSessionTemplate = context.getBean("sessionTemplate", SqlSessionTemplate.class); UserDao mapper = sqlSessionTemplate.getMapper(UserDao.class); List<User> userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } }