Java SSM4——Spring
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)
Spring的优势
- 方便解耦,简化开发
- Spring就是一个容器,可以将所有对象创建和关系维护交给Spring管理 什么是耦合度?对象之间的关系,通常说当一个模块(对象)更改时也需要更改其他模块(对象),这就是耦合,耦合度过高会使代码的维护成本增加。要尽量解耦
- AOP编程的支持
- Spring提供面向切面编程,方便实现程序进行权限拦截,运行监控等功能
- 声明式事务的支持
- 通过配置完成事务的管理,无需手动编程
- 方便测试,降低JavaEE API
- 的使用 Spring对Junit4支持,可以使用注解测试
- 方便集成各种优秀框架
- 不排除各种优秀的开源框架,内部提供了对各种优秀框架的直接支持
1、IOC
Inverse Of Control:控制反转:配置文件(解除硬编码)+反射(解除编译器依赖)
- 控制:在java中指的是对象的控制权限(创建、销毁)
- 反转:指的是对象控制权由原来 由开发者在类中手动控制交由Spring管理
2、AOP
Aspect Oriented Programming:面向切面编程:动态代理(方法增强)
3、快速入门
默认为maven项目
3.1、导入依赖
<dependencies>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
3.2、Spring核心配置文件
如无特殊需求,我们默认spring核心配置文件名为applicationContent.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="HelloSpring" class="club.winkto.bean.HelloSpring"></bean>
</beans>
3.3、书写简单的类
public class HelloSpring {
public void hellospring(){
System.out.println("hello spring!");
}
}
3.4、测试
@Test
public void test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("applicationContent.xml");
HelloSpring hellospring = classPathXmlApplicationContext.getBean("hellospring", HelloSpring.class);
hellospring.hellospring();
}
4、Spring API
BeanFactory也可以完成ApplicationContext完成的事情,为什么我们要选择ApplicationContext?
BeanFactory:在第一次调用getBean()方法时,创建指定对象的实例
ApplicationContext:在spring容器启动时,加载并创建所有对象的实例
4.1、常用实现类
- ClassPathXmlApplicationContext 它是从类的根路径下加载配置文件 推荐使用这种
- FileSystemXmlApplicationContext 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
- AnnotationConfigApplicationContext 当使用注解配置容器对象时,需要使用此类来创建 spring 容器,它用来读取注解
5、Spring IOC
5.1、bean
5.1.1、基础使用
<bean id="" class=""></bean>
- id:Bean实例在Spring容器中的唯一标识
- class:Bean的全限定名
- 默认情况下它调用的是类中的 无参构造函数,如果没有无参构造函数则不能创建成功
5.1.2、scope属性
<bean id="" class="" scope=""></bean>
- singleton:单例(默认)
- 对象创建:当应用加载,创建容器时,对象就被创建了
- 对象运行:只要容器在,对象一直活着
- 对象销毁:当应用卸载,销毁容器时,对象就被销毁了
- prototype:多例
- 对象创建:当使用对象时,创建新的对象实例
- 对象运行:只要对象在使用中,就一直活着
- 对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了
5.1.3、生命周期的配置
<bean id="" class="包名.类名" init-method="指定class的方法" destroy-method="指定class的方法"></bean>
- init-method:指定类中的初始化方法名称
- destroy-method:指定类中销毁方法名称
5.1.4、实例化的三种方式
5.1.4.1、无参构造方法实例化
上述即是
5.1.4.2、工厂静态方法实例化
<bean id="" class="包名.类名" factory-method="指定class的方法" />
5.1.4.3、工厂静态方法实例化
<bean id="工厂类id" class="包名.类名"/>
<bean id="" factory-bean="工厂类id" factorymethod="工厂类id里的方法"/>
5.1.5、别名
5.1.5.1、alias标签
<alias name="hello" alias="hello1"></alias>
5.1.5.2、bean标签name属性
<bean id="HelloSpring" name="hello2 h2,h3;h4" class="club.winkto.bean.HelloSpring"></bean>
可写多个别名,分隔符为空格,逗号,分号均可
5.2、依赖注入(DI)
Spring 框架核心 IOC 的具体实现
5.2.1、构造方法
mapper
public interface WinktoMapper {
void mapper();
}
public class WinktoMapperImpl implements WinktoMapper {
public void mapper() {
System.out.println("假装自己有了数据库查询");
}
}
service
public interface WinktoService {
void service();
}
public class WinktoServiceImpl implements WinktoService {
private int a;
private WinktoMapperImpl winktoMapper;
private Object[] arrays;
private List list;
private Map<String,Object> map;
private Set set;
private Properties properties;
public WinktoServiceImpl(int a, WinktoMapperImpl winktoMapper, Object[] arrays, List list, Map<String, Object> map, Set set, Properties properties) {
this.a = a;
this.winktoMapper = winktoMapper;
this.arrays = arrays;
this.list = list;
this.map = map;
this.set = set;
this.properties = properties;
}
public void service() {
System.out.println("假装自己开启了事务");
winktoMapper.mapper();
System.out.println("=================");
System.out.println(toString());
System.out.println("=================");
System.out.println("假装自己提交了事务");
}
@Override
public String toString() {
return "WinktoServiceImpl{" +
"a=" + a +
", winktoMapper=" + winktoMapper +
", arrays=" + arrays +
", list=" + list +
", map=" + map +
", set=" + set +
", properties=" + properties +
'}';
}
}
aplicationContent.xml
<bean id="winktoMapper" class="club.winkto.mapper.WinktoMapperImpl">
</bean>
<bean id="winktoService" class="club.winkto.service.WinktoServiceImpl">
<!--<constructor-arg index="0" value="12"></constructor-arg>-->
<!--<constructor-arg index="1" ref="winktoMapper"></constructor-arg>-->
<!--<constructor-arg index="2">-->
<!-- <array>-->
<!-- <value>1</value>-->
<!-- <ref bean="winktoMapper"></ref>-->
<!-- </array>-->
<!--</constructor-arg>-->
<!--<constructor-arg index="3">-->
<!-- <list>-->
<!-- <value>2</value>-->
<!-- <ref bean="winktoMapper"></ref>-->
<!-- </list>-->
<!--</constructor-arg>-->
<!--<constructor-arg index="4">-->
<!-- <map>-->
<!-- <entry key="name" value="zhangsan"></entry>-->
<!-- <entry key="service" value-ref="winktoMapper"></entry>-->
<!-- </map>-->
<!--</constructor-arg>-->
<!--<constructor-arg index="5">-->
<!-- <set>-->
<!-- <value>3</value>-->
<!-- <ref bean="winktoMapper"></ref>-->
<!-- </set>-->
<!--</constructor-arg>-->
<!--<constructor-arg index="6">-->
<!-- <props>-->
<!-- <prop key="name">zhangsan</prop>-->
<!-- </props>-->
<!--</constructor-arg>-->
<constructor-arg name="a" value="12"></constructor-arg>
<constructor-arg name="winktoMapper" ref="winktoMapper"></constructor-arg>
<constructor-arg name="arrays">
<array>
<value>1</value>
<ref bean="winktoMapper"></ref>
</array>
</constructor-arg>
<constructor-arg name="list">
<list>
<value>2</value>
<ref bean="winktoMapper"></ref>
</list>
</constructor-arg>
<constructor-arg name="map">
<map>
<entry key="name" value="zhangsan"></entry>
<entry key="service" value-ref="winktoMapper"></entry>
</map>
</constructor-arg>
<constructor-arg name="set">
<set>
<value>3</value>
<ref bean="winktoMapper"></ref>
</set>
</constructor-arg>
<constructor-arg name="properties">
<props>
<prop key="name">zhangsan</prop>
</props>
</constructor-arg>
</bean>
</beans>
测试
@Test
public void test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("applicationContent.xml");
WinktoService winktoService = classPathXmlApplicationContext.getBean("winktoService", WinktoService.class);
winktoService.service();
}
5.2.2、set
mapper
public interface WinktoMapper {
void mapper();
}
public class WinktoMapperImpl implements WinktoMapper {
public void mapper() {
System.out.println("假装自己有了数据库查询");
}
}
service
public interface WinktoService {
void service();
}
public class WinktoServiceImpl implements WinktoService {
private int a;
private WinktoMapperImpl winktoMapper;
private Object[] arrays;
private List list;
private Map<String,Object> map;
private Set set;
private Properties properties;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public WinktoMapperImpl getWinktoMapper() {
return winktoMapper;
}
public void setWinktoMapper(WinktoMapperImpl winktoMapper) {
this.winktoMapper = winktoMapper;
}
public Object[] getArrayList() {
return arrays;
}
public void setArrayList(Object[] arrays) {
this.arrays = arrays;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
public Set getSet() {
return set;
}
public void setSet(Set set) {
this.set = set;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void service() {
System.out.println("假装自己开启了事务");
winktoMapper.mapper();
System.out.println("=================");
System.out.println(toString());
System.out.println("=================");
System.out.println("假装自己提交了事务");
}
@Override
public String toString() {
return "WinktoServiceImpl{" +
"a=" + a +
", winktoMapper=" + winktoMapper +
", arrays=" + arrays +
", list=" + list +
", map=" + map +
", set=" + set +
", properties=" + properties +
'}';
}
}
aplicationContent.xml
<bean id="winktoMapper" class="club.winkto.mapper.WinktoMapperImpl">
</bean>
<bean id="winktoService" class="club.winkto.service.WinktoServiceImpl">
<property name="a" value="12"></property>
<property name="winktoMapper" ref="winktoMapper"></property>
<property name="arrayList">
<array>
<value>1</value>
<ref bean="winktoMapper"></ref>
</array>
</property>
<property name="list">
<list>
<value>2</value>
<ref bean="winktoMapper"></ref>
</list>
</property>
<property name="map">
<map>
<entry key="name" value="zhangsan"></entry>
<entry key="service" value-ref="winktoMapper"></entry>
</map>
</property>
<property name="set">
<set>
<value>3</value>
<ref bean="winktoMapper"></ref>
</set>
</property>
<property name="properties">
<props>
<prop key="name">zhangsan</prop>
</props>
</property>
</bean>
测试
@Test
public void test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("applicationContent.xml");
WinktoService winktoService = classPathXmlApplicationContext.getBean("winktoService", WinktoService.class);
winktoService.service();
}
5.2.3、p命名空间(简单示范)
导入约束
xmlns:p="http://www.springframework.org/schema/p"
mapper
public interface WinktoMapper {
void mapper();
}
public class WinktoMapperImpl implements WinktoMapper {
public void mapper() {
System.out.println("假装自己有了数据库查询");
}
}
service
public interface WinktoService {
void service();
}
public class WinktoServiceImpl implements WinktoService {
private WinktoMapperImpl winktoMapper;
public WinktoMapperImpl getWinktoMapper() {
return winktoMapper;
}
public void setWinktoMapper(WinktoMapperImpl winktoMapper) {
this.winktoMapper = winktoMapper;
}
public void service() {
System.out.println("假装自己开启了事务");
winktoMapper.mapper();
System.out.println("假装自己提交了事务");
}
}
aplicationContent.xml
- 对于bean引用用p:xxx-ref
- 否则使用p:xxx
<bean id="winktoMapper" class="club.winkto.mapper.WinktoMapperImpl">
</bean>
<bean id="winktoService" class="club.winkto.service.WinktoServiceImpl" p:winktoMapper-ref="winktoMapper">
</bean>
测试
@Test
public void test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("applicationContent.xml");
WinktoService winktoService = classPathXmlApplicationContext.getBean("winktoService", WinktoService.class);
winktoService.service();
}
5.2.4、c命名空间(简单示范)
导入约束
xmlns:c="http://www.springframework.org/schema/c"
mapper
public interface WinktoMapper {
void mapper();
}
public class WinktoMapperImpl implements WinktoMapper {
public void mapper() {
System.out.println("假装自己有了数据库查询");
}
}
service
public interface WinktoService {
void service();
}
public class WinktoServiceImpl implements WinktoService {
private WinktoMapperImpl winktoMapper;
public WinktoMapperImpl getWinktoMapper() {
return winktoMapper;
}
public void setWinktoMapper(WinktoMapperImpl winktoMapper) {
this.winktoMapper = winktoMapper;
}
public void service() {
System.out.println("假装自己开启了事务");
winktoMapper.mapper();
System.out.println("假装自己提交了事务");
}
}
aplicationContent.xml
- 对于bean引用用c:xxx-ref
- 否则使用c:xxx
- c命名空间可以额外使用c:_0-ref
<bean id="winktoMapper" class="club.winkto.mapper.WinktoMapperImpl">
</bean>
<!--<bean id="winktoService" class="club.winkto.service.WinktoServiceImpl" c:winktoMapper-ref="winktoMapper">-->
<!--</bean>-->
<bean id="winktoService" class="club.winkto.service.WinktoServiceImpl" c:_0-ref="winktoMapper">
</bean>
测试
@Test
public void test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("applicationContent.xml");
WinktoService winktoService = classPathXmlApplicationContext.getBean("winktoService", WinktoService.class);
winktoService.service();
}
5.3、配置文件模块化
5.3.1、配置文件并列
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("applicationContent.xml","beans.xml");
5.3.2、主从配置文件
在applicationContent.xml导入beans.xml
<import resource="beans.xml"/>
6、Spring注解开发(IOC部分)
Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代 替xml配置文件可以简化配置,提高开发效率
开启注解扫描
<!--注解的组件扫描-->
<context:component-scan base-package="club.winkto"></context:component-scan>
6.1、注册bean
注解 | 说明 |
---|---|
@Component | 使用在类上用于实例化Bean |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
6.2、依赖注入
注解 | 说明 |
---|---|
@Autowired | 使用在字段上用于根据类型依赖注入(先根据type,类型不唯一根据name自动装配的) |
@Qualifier | 结合@Autowired一起使用,根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入(很少用且jdk11在spring核心包不包含此注解) |
@Value | 注入普通属性(也可以注入spring配置文件里的其他普通属性使用${},上面三个注入引用类型) |
6.3、初始销毁
注解 | 说明 |
---|---|
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
6.4、新注解
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个Spring 配置类,当创建容器时会从该类上加载注解 |
@Bean | 使用在方法上,标注将该方法的返回值存储到 Spring 容器中 |
@PropertySource | 用于加载 properties 文件中的配置 |
@ComponentScan | 用于指定 Spring 在初始化容器时要扫描的包 |
@Import | 用于导入其他配置类 |
6.5、注解快速入门
mapper
public interface WinktoMapper {
void mapper();
}
@Repository("winktoMapper")
public class WinktoMapperImpl implements WinktoMapper {
public void mapper() {
System.out.println("假装自己有了数据库查询");
}
}
service
public interface WinktoService {
void service();
}
@Service("winktoService")
public class WinktoServiceImpl implements WinktoService {
@Value("12")
private int a;
@Autowired
private WinktoMapperImpl winktoMapper;
public WinktoServiceImpl() {
}
public WinktoServiceImpl(int a, WinktoMapperImpl winktoMapper) {
this.a = a;
this.winktoMapper = winktoMapper;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public WinktoMapperImpl getWinktoMapper() {
return winktoMapper;
}
public void setWinktoMapper(WinktoMapperImpl winktoMapper) {
this.winktoMapper = winktoMapper;
}
public void service() {
System.out.println("假装自己开启了事务");
winktoMapper.mapper();
System.out.println("=================");
System.out.println(toString());
System.out.println("=================");
System.out.println("假装自己提交了事务");
}
@Override
public String toString() {
return "WinktoServiceImpl{" +
"a=" + a +
", winktoMapper=" + winktoMapper +
'}';
}
}
aplicationContent.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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
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
https://www.springframework.org/schema/context/spring-context.xsd">
<!--注解的组件扫描-->
<context:component-scan base-package="club.winkto"></context:component-scan>
</beans>
测试
@Test
public void test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("applicationContent.xml");
WinktoService winktoService = classPathXmlApplicationContext.getBean("winktoService", WinktoService.class);
winktoService.service();
}
6.6、纯注解开发
导入依赖
<dependencies>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
</dependencies>
mapper
public interface WinktoMapper {
void mapper();
}
@Repository("winktoMapper")
public class WinktoMapperImpl implements WinktoMapper {
@Value("${name}")
private String name;
public void mapper() {
System.out.println(name);
System.out.println("假装自己有了数据库查询");
}
}
service
public interface WinktoService {
void service();
}
@Service("winktoService")
public class WinktoServiceImpl implements WinktoService {
@Value("12")
private int a;
@Autowired
private WinktoMapperImpl winktoMapper;
public WinktoServiceImpl() {
}
public WinktoServiceImpl(int a, WinktoMapperImpl winktoMapper) {
this.a = a;
this.winktoMapper = winktoMapper;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public WinktoMapperImpl getWinktoMapper() {
return winktoMapper;
}
public void setWinktoMapper(WinktoMapperImpl winktoMapper) {
this.winktoMapper = winktoMapper;
}
public void service() {
System.out.println("假装自己开启了事务");
winktoMapper.mapper();
System.out.println("=================");
System.out.println(toString());
System.out.println("=================");
System.out.println("假装自己提交了事务");
}
@Override
public String toString() {
return "WinktoServiceImpl{" +
"a=" + a +
", winktoMapper=" + winktoMapper +
'}';
}
}
config
@Configuration
@PropertySource("classpath:database.properties")
public class WinktoMapperConfig {
@Value("${name}")
private String name;
}
@Configuration
@ComponentScan("club.winkto")
@Import(WinktoMapperConfig.class)
public class WinktoConfig {
@Bean
public ObjectMapper objectMapper(){
return new ObjectMapper();
}
}
测试
@Test
public void test() throws JsonProcessingException {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(WinktoConfig.class);
WinktoService winktoService = annotationConfigApplicationContext.getBean("winktoService", WinktoService.class);
ObjectMapper objectMapper = annotationConfigApplicationContext.getBean("objectMapper", ObjectMapper.class);
System.out.println(objectMapper.writeValueAsString(winktoService));
winktoService.service();
}
6.7、Spring整合junit
导入依赖
<dependencies>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
<!--spring-test-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
</dependencies>
修改Test类
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(value = {"classpath:applicationContext.xml"})
@ContextConfiguration(classes = {WinktoConfig.class})
public class MyTest {
@Autowired
private WinktoService winktoService;
@Autowired
private ObjectMapper objectMapper;
@Test
public void test() throws JsonProcessingException {
System.out.println(objectMapper.writeValueAsString(winktoService));
winktoService.service();
}
}
7、动态代理
7.1、JDK动态代理
基于接口的动态代理技术:利用拦截器(必须实现invocationHandler)加上反射机制生成 一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,从而实现方法增强
7.2.1、JDK动态代理实现
service
public interface CRUD {
void select();
void insert();
void update();
void delete();
}
@Service
public class CRUDService implements CRUD {
public void select() {
System.out.println("假装自己执行了select");
}
public void insert() {
System.out.println("假装自己执行了insert");
}
public void update() {
System.out.println("假装自己执行了update");
}
public void delete() {
System.out.println("假装自己执行了delete");
}
}
config
@Configuration
@ComponentScan("cn.winkto")
public class WinktoConfig {
@Bean("objectMapper")
public ObjectMapper getObjectMapper(){
return new ObjectMapper();
}
}
代理
@Component
public class JDKProxy {
public Object proxy(final CRUDService crudService){
return Proxy.newProxyInstance(crudService.getClass().getClassLoader(), crudService.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理前");
Object invoke = method.invoke(crudService, args);
System.out.println("代理后");
return invoke;
}
});
}
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WinktoConfig.class})
public class MyTest {
@Autowired
private JDKProxy jdkProxy;
@Autowired
private CRUDService crudService;
@Test
public void test(){
CRUD proxy = (CRUD) jdkProxy.proxy(crudService);
proxy.select();
}
}
7.2、CGLIB代理
基于父类的动态代理技术:动态生成一个要代理的子类,子类重写要代理的类的所有不是 final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,对方法进行 增强
7.2.1、CGLIB代理的实现
service
public interface CRUD {
void select();
void insert();
void update();
void delete();
}
@Service
public class CRUDService implements CRUD {
public void select() {
System.out.println("假装自己执行了select");
}
public void insert() {
System.out.println("假装自己执行了insert");
}
public void update() {
System.out.println("假装自己执行了update");
}
public void delete() {
System.out.println("假装自己执行了delete");
}
}
config
@Configuration
@ComponentScan("cn.winkto")
public class WinktoConfig {
@Bean("objectMapper")
public ObjectMapper getObjectMapper(){
return new ObjectMapper();
}
}
代理
@Component
public class CglibProxy {
public Object proxy(final CRUDService crudService){
return Enhancer.create(crudService.getClass(), new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理前");
Object invoke = method.invoke(crudService, objects);
System.out.println("代理后");
return invoke;
}
});
}
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WinktoConfig.class})
public class MyTest {
@Autowired
private JDKProxy jdkProxy;
@Autowired
private CglibProxy cglibProxy;
@Autowired
private CRUDService crudService;
@Test
public void test1(){
CRUD proxy = (CRUD) cglibProxy.proxy(crudService);
proxy.select();
}
}
8、Spring AOP
AOP 是 OOP(面向对象编程) 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
- 在程序运行期间,在不修改源码的情况下对方法进行功能增强
- 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
- 减少重复代码,提高开发效率,便于后期维护
8.1、Aop术语解释
- Target(目标对象):代理的目标对象
- Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
- Joinpoint(连接点):所谓连接点是指那些可以被拦截到的点。在spring中,这些点指的是方法,因为 spring只支持方法类型的连接点
- Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
- Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知 分类:前置通知、后置通知、异常通知、最终通知、环绕通知
- Aspect(切面):是切入点和通知(引介)的结合
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织 入,而AspectJ采用编译期织入和类装载期织入
8.2、Aop快速入门
导入依赖
<dependencies>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
<!--spring-test-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.9</version>
<scope>test</scope>
</dependency>
<!--aop-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
</dependencies>
service
public interface CRUD {
void select();
void insert();
void update();
void delete();
}
public class CRUDService implements CRUD {
public void select() {
System.out.println("假装自己执行了select");
}
public void insert() {
System.out.println("假装自己执行了insert");
}
public void update() {
System.out.println("假装自己执行了update");
}
public void delete() {
System.out.println("假装自己执行了delete");
}
}
aop
public class CRUDAdvice {
public void before(){
System.out.println("前置通知");
}
public void afterReturning(){
System.out.println("后置通知");
}
public void afterThrowing(){
System.out.println("异常通知");
}
public void after(){
System.out.println("最终通知");
}
public void around(ProceedingJoinPoint ProceedingJoinPoint){
System.out.println("环绕开始");
try {
ProceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("环绕结束");
}
}
applicationContent.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: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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="crudService" class="cn.winkto.service.CRUDService"></bean>
<bean id="crudAdvice" class="cn.winkto.aop.CRUDAdvice"></bean>
<aop:config>
<aop:aspect ref="crudAdvice">
<aop:before method="before" pointcut="execution(* cn.winkto.service.CRUDService.*(..))"></aop:before>
<aop:after method="afterReturning" pointcut="execution(* cn.winkto.service.CRUDService.*(..))"></aop:after>
</aop:aspect>
</aop:config>
</beans>
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:applicationContent.xml"})
public class MyTest {
@Autowired
private CRUD crud;
@Test
public void test(){
crud.select();
}
}
8.3、Aop详解
8.3.1、切点表达式
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
- 访问修饰符可以省略
- 返回值类型、包名、类名、方法名可以使用星号 * 代替,代表任意
- 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
- 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表
8.3.2、切点表达式的抽取
<?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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="crudService" class="cn.winkto.service.CRUDService"></bean>
<bean id="crudAdvice" class="cn.winkto.aop.CRUDAdvice"></bean>
<aop:config>
<aop:aspect ref="crudAdvice">
<aop:pointcut id="point1" expression="execution(* cn.winkto.service.CRUDService.*(..))"/>
<aop:before method="before" pointcut-ref="point1"></aop:before>
<aop:after method="afterReturning" pointcut-ref="point1"></aop:after>
</aop:aspect>
</aop:config>
</beans>
<?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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="crudService" class="cn.winkto.service.CRUDService"></bean>
<bean id="crudAdvice" class="cn.winkto.aop.CRUDAdvice"></bean>
<aop:config>
<aop:pointcut id="point1" expression="execution(* cn.winkto.service.CRUDService.*(..))"/>
<aop:aspect ref="crudAdvice">
<aop:before method="before" pointcut-ref="point1"></aop:before>
<aop:after method="afterReturning" pointcut-ref="point1"></aop:after>
</aop:aspect>
</aop:config>
</beans>
8.3.3、通知类型
<aop:通知类型 method=“通知类中方法名” pointcut=“切点表达式"></aop:通知类型>
名称 | 标签 | 说明 |
---|---|---|
前置通知 | <aop:before> | 用于配置前置通知,指定增强的方法在切入点方法之前执行 |
后置通知 | <aop:afterReturning> | 用于配置后置通知。指定增强的方法在切入点方法之后执行 |
异常通知 | <aop:afterThrowing> | 用于配置异常通知。指定增强的方法出现异常后执行 |
最终通知 | <aop:after> | 用于配置最终通知。无论切入点方法执行时是否有异常,都会执行 |
环绕通知 | <aop:around> | 用于配置环绕通知。开发者可以手动控制增强代码在什么时候执行 |
后置通知与异常通知互斥,环绕通知一般独立使用
9、Spring注解开发(AOP部分)
导入依赖
<dependencies>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
<!--spring-test-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.9</version>
<scope>test</scope>
</dependency>
<!--aop-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
</dependencies>
service
public interface CRUD {
void select();
void insert();
void update();
void delete();
}
public class CRUDService implements CRUD {
public void select() {
System.out.println("假装自己执行了select");
}
public void insert() {
System.out.println("假装自己执行了insert");
}
public void update() {
System.out.println("假装自己执行了update");
}
public void delete() {
System.out.println("假装自己执行了delete");
}
}
aop
@Component
//标注为切面类
@Aspect
public class CRUDAdvice {
@Pointcut("execution(* cn.winkto.service.CRUDService.*(..))")
public void point(){
}
@Before("point()")
public void before(){
System.out.println("前置通知");
}
@AfterReturning("point()")
public void afterReturning(){
System.out.println("后置通知");
}
public void afterThrowing(){
System.out.println("异常通知");
}
public void after(){
System.out.println("最终通知");
}
public void around(ProceedingJoinPoint ProceedingJoinPoint){
System.out.println("环绕开始");
try {
ProceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("环绕结束");
}
}
config
@Configuration
@ComponentScan("cn.winkto")
//开启自动aop代理
@EnableAspectJAutoProxy
public class WinktoConfig {
@Bean("objectMapper")
public ObjectMapper getObjectMapper(){
return new ObjectMapper();
}
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WinktoConfig.class})
public class MyTest {
@Autowired
private CRUD crud;
@Test
public void test(){
crud.select();
}
}
10、Spring事务
- 编程式事务:直接把事务的代码和业务代码耦合到一起,在实际开发中不用(下文不进行详细阐述)
- 声明式事务:采用配置的方式来实现的事务控制,业务代码与事务代码实现解耦合
10.1、声明式事务(基于XML,整合mybatis)
实体类
public class Person {
private int pid;
private String pname;
private String ppassword;
}
mapper
public interface PersonMapper {
List<Person> selectPerson();
}
public class PersonMapperImpl implements PersonMapper {
private SqlSession sqlSession;
public PersonMapperImpl(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
public List<Person> selectPerson() {
return sqlSession.getMapper(PersonMapper.class).selectPerson();
}
}
映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.winkto.mapper.PersonMapper">
<select id="selectPerson" resultType="Person">
select * from person
</select>
</mapper>
数据库配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone =Asia/Shanghai
user=root
password=blingbling123.
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>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="cn.winkto.bean"></package>
</typeAliases>
<mappers>
<package name="cn.winkto.mapper"/>
</mappers>
</configuration>
spring配置文件
<?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" xmlns:tx="http://www.springframework.org/schema/tx"
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/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="cn.winkto" />
<context:property-placeholder location="classpath:database.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="mybatis-config.xml" />
</bean>
<!--sqlsession-->
<bean id="sqlsession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="personMapper" class="cn.winkto.mapper.PersonMapperImpl">
<constructor-arg name="sqlSession" ref="sqlsession" />
</bean>
<!--事务管理器-->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg name="dataSource" ref="dataSource" />
</bean>
<!--通知增强-->
<tx:advice id="txAdvice" transaction-manager="tx">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--织入事务-->
<aop:config>
<aop:pointcut id="point" expression="execution(* cn.winkto.mapper.PersonMapperImpl.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="point" />
</aop:config>
</beans>
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:applicationContent.xml"})
public class MyTest {
@Autowired
private PersonMapper personMapper;
@Test
public void test(){
System.out.println(personMapper.selectPerson());
}
}
10.1.1、 事务参数的配置详解
<tx:method name="selectPerson" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
- name:切点方法名称(可以使用*做匹配,类似于模糊查询)
- isolation:事务的隔离级别
- propogation:事务的传播行为
- timeout:超时时间
- read-only:是否只读
10.2、声明式事务(基于注解,整合mybatis)
实体类
public class Person {
private int pid;
private String pname;
private String ppassword;
}
数据库配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone =Asia/Shanghai
user=root
password=blingbling123.
mapper
public interface PersonMapper {
List<Person> selectPerson();
}
@Repository("personMapper")
public class PersonMapperImpl implements PersonMapper {
@Autowired
private SqlSessionTemplate sqlSession;
public PersonMapperImpl(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
//配置事务属性(可放置在类上,k)
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout = -1,readOnly = true)
public List<Person> selectPerson() {
return sqlSession.getMapper(PersonMapper.class).selectPerson();
}
}
映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.winkto.mapper.PersonMapper">
<select id="selectPerson" resultType="Person">
select * from person
</select>
</mapper>
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>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="cn.winkto.bean"></package>
</typeAliases>
<mappers>
<package name="cn.winkto.mapper"/>
</mappers>
</configuration>
config
@Configuration
@EnableAspectJAutoProxy
@EnableTransactionManagement
@ComponentScan("cn.winkto")
@PropertySource("classpath:database.properties")
public class WinktoConfig {
@Value("${driver}")
private String driver;
@Value("${url}")
private String url;
@Value("${user}")
private String user;
@Value("${password}")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(user);
druidDataSource.setPassword(password);
return druidDataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(@Autowired DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
return sqlSessionFactoryBean;
}
@Bean("sqlSession")
public SqlSessionTemplate sqlSessionTemplate(@Autowired SqlSessionFactoryBean sqlSessionFactoryBean) throws Exception {
return new SqlSessionTemplate(sqlSessionFactoryBean.getObject());
}
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(){
return new DataSourceTransactionManager(dataSource());
}
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WinktoConfig.class})
public class MyTest {
@Autowired
private PersonMapper personMapper;
@Test
public void test(){
System.out.println(personMapper.selectPerson());
}
}