文章目录
1、Spring环境搭建
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
1.1、IOC(控制反转)
-
控制翻转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式,在Spring中实现控制反转的是IoC容器,其实现方式是依赖注入(Dependency Injection)
讲人话就是:需要对象不用自己手动去创建,Spring帮你来创建,管理,装配。 -
当需要修改时,只需要修改
beans.xml
中标签的属性值,不用去修改代码。 -
之前是主动创建对象,控制权在程序员手上。
-
使用set之后,是被动接受对象。
2、HelloSpring
POJO中
package com.stjp.pojo;
public class MySpring {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "MySpring{" +
"name='" + name + '\'' +
'}';
}
}
beans.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:变量名
class:new的对象
property:相当于给对象的属性设值
-->
<bean id="hello" class="com.stjp.pojo.MySpring">
<property name="name" value="stjp"/>
</bean>
<bean id="bye" class="com.stjp.pojo.MyT">
<property name="mySpring" ref="hello"/>
</bean>
</beans>
-
bean:对象
-
id:变量名
-
class:new的对象
-
property:相当于给对象的属性设值
4.1.value为普通值
4.2.ref为引用值
Test中
mport com.stjp.pojo.MySpring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
//代表Spring容器,一旦创建所有的bean都会被实例化
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//想使用哪个根据id获取即可
MySpring hello = (MySpring) context.getBean("hello");
System.out.println(hello.toString());
}
}
3、IOC创建对象方式
-
使用无参构造创建对象,默认。
-
使用有参构造
法一:下标赋值
<bean id="hello" class="com.stjp.pojo.MySpring">
<constructor-arg index="0" value="stjp"/>
</bean>
法二:类型赋值(不建议使用)
<bean id="hello" class="com.stjp.pojo.MySpring">
<constructor-arg type="java.lang.String" value="stjp"/>
</bean>
法三:直接通过参数名
<bean id="hello" class="com.stjp.pojo.MySpring">
<constructor-arg name="name" value="stjp"/>
</bean>
4、Spring的配置
alias(别名)
<bean id="user" class="com.hou.pojo.User">
<constructor-arg name="name" value="hou"></constructor-arg>
</bean>
<alias name="user" alias="user2aaa"/>
bean
- id:bean的id标识符
- class:bean对象所对应的类型
- name:别名,更高级,可以同时取多个别名。
import(同id后面添加的bean会覆盖前面)
一般用于团队开发,它可以将多个配置文件,导入合并为一个
<import resource="beans.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>
<import resource="beans4.xml"/>
5、DI依赖注入
5.1构造器注入(前面)
5.2 Set注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,由容器来注入
复杂环境搭建
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbies;
private Map<String, String> card;
private Set<String> game;
private Properties infor;
private String wife;
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address +
", books=" + Arrays.toString(books) +
", hobbies=" + hobbies +
", card=" + card +
", game=" + game +
", infor=" + infor +
", wife='" + wife + '\'' +
'}';
}
}
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address + '\'' +
'}';
}
}
beans.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="address" class="com.stjp.pojo.Address">
<property name="address" value="江门"/>
</bean>
<bean id="student" class="com.stjp.pojo.Student">
<property name="name" value="张三"/>
<property name="address" ref="address"/>
<property name="books">
<array>
<value>语文</value>
<value>数学</value>
<value>英语</value>
</array>
</property>
<property name="hobbies">
<list>
<value>打球</value>
<value>跑步</value>
<value>游泳</value>
</list>
</property>
<property name="card">
<map>
<entry key="身份证" value="156479833124689"/>
<entry key="校园卡" value="21564321"/>
</map>
</property>
<property name="game">
<set>
<value>lol</value>
<value>cf</value>
<value>dnf</value>
</set>
</property>
<property name="infor">
<props>
<prop key="学生id">1547852</prop>
</props>
</property>
<property name="wife">
<null/>
</property>
</bean>
</beans>
map和properties有差别
6、Bean的自动装配
- 自动装配是Spring是满足bean依赖的一种方式
- Spring会在上下文自动寻找,并自动给bean装配属性
在Spring中有三种装配的方式
- 在xml中显示配置
- Byname自动装配:byname会自动查找,找和自己对象set方法名字对应的id值匹配
- Bytype自动装配:byType会自动查找,和自己对象属性相同的bean,保证所有的class唯一
- 在java中显示配置
- 隐式的自动装配bean 【重要】
环境
<?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 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:annotation-config/>
</beans>
6.1、@Autowired
- 先ByType自动装配找不到再使用ByName自动装配
- 常与**@Qualifier(value = “xxx”)**一起使用,限定使用id为xxx的bean
相当于省略了两个Property
<bean id="cat" class="pojo/Cat"/>
<bean id="dog" class="pojo/Dog"/>
<bean id="people" class="pojo/People" autowire="byName">
<property name="name" value="Lewis"/>
//<property name="cat" ref="cat"/>自动装配会自动完成,这两行代码可以省略
//<property name="dog" ref="dog"/>
</bean>
6.2、 @Resource
- 先ByType自动装配找不到再使用ByName自动装配
- 可以用@Resource(name=“xxx”)来限定使用id为xxx的bean
6.3、@Autowired和@Resource的区别
- @Autowired可以使用在set方法上
- @Autowired使用在属性上时,可以省略set方法
7、使用注解开发
在spring4之后,必须要保证aop的包导入
使用注解需要导入contex的约束
<?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 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:annotation-config/>
//要扫描的包
<context:component-scan base-package="com.stjp.pojo"/>
</beans>
7.1、@Component!!!
- 对整个类进行装配。衍生出
@Respository,@Service,@Controller
,分别用在Dao层、Service层、Controller层的类上,效果一样。所有属性不用写get/set方法
- 相对于注册了bean
- bean的id就是这个类名的小写
相当于
<bean id="people" class="com.stjp.pojo.People" />
7.2、@Value
用在属性上,给属性赋值
7.2、小结
- XML更加万能,适用于任何场合,维护简单方便!
- 注解不是自己的类使用不了,维护相对复杂
- xml用来管理bean,注解只完成属性的注入。
8、JavaConfig
Spring的一个子项目,在spring4之后,,他成为了核心功能
两种方式:
- 使用@Component和@ComponentScan(“pojo”)
- 使用@Configuration和@bean(主流)
8.1、@Configuration和@bean
@Configuration
public class Config {
@Bean("user")
public User getuser(){
return new User();
}
}
public class User {
@Value("stttt")
private String name;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
- @Configuration相当于作为xml,作为一个 Spring 的容器来使用,用于完成 Bean 的创建
- @bean相当于注册一个bean,id默认为方法名
8.2、@Component和@ComponentScan(“pojo”)
@ComponentScan("pojo")
public class Config {
}
@Component
public class User {
@Value("stttt")
private String name;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
- @Component相当于注册一个bean,默认id为类名小写
- @ComponentScan(“pojo”)相当于作为xml并且扫描包
8.3、注意
- 如果使用注解配置类的方式去做,我们只能通过AnnotationConfigApplicationContext来获取容器
9、代理模式
9.1、静态代理
加多一层,解耦合
9.2、动态代理[*]
java动态代理机制中有两个重要的类和接口InvocationHandler(接口)和Proxy(类),这一个类Proxy和接口InvocationHandler是我们实现动态代理的核心
- 自己编写并继承InvocationHandler接口的类被称为proxy代理实例的调用处理程序
9.2.1、InvocationHandler接口
-
InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。
-
当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用
/** * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0 * method:我们所要调用某个对象真实的方法的Method对象 * args:指代代理对象方法传递的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
9.2.2、Proxy类
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
-
**loader:**类加载器
-
**interfaces:**你要代理的类所实现的接口
-
**h:**一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。
Service接口
public interface Service { void add(); void delete();}
ServiceImpl类
public class ServiceImpl implements Service{ @Override public void add() { System.out.println("使用了add方法"); } @Override public void delete() { System.out.println("使用了delete方法"); }}
代理类调用处理程序类
public class ProxyHandler implements InvocationHandler {
//获取代理类所实现的接口
private Service service;
public void setService(Service service) {
this.service = service;
}
//获取代理类对象
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), service.getClass().getInterfaces(),this);
}
//代理对象调用代理类方法时会自动进入此方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName());
Object invoke = method.invoke(service, args);
return invoke;
}
}
测试类
public class MyTest {
public static void main(String[] args) {
ServiceImpl service = new ServiceImpl();
//获取代理程序
ProxyHandler proxyHandler = new ProxyHandler();
//获取代理类并实现要代理类的接口
proxyHandler.setService(service);
Service proxy = (Service) proxyHandler.getProxy();
proxy.add();
}
}
https://blog.csdn.net/yaomingyang/article/details/80981004
10、AOP[重点]
面向切面编程
AOP的核心是动态代理
-
横切关注点:横跨多个模块的方法或功能,待加入到业务层实现功能扩充,如日志功能
-
切面(aspect):横切关注点被模块化的特殊对象,是一个类,即下文中的afterLog类
-
通知(advice):切面必须完成的工作,即类中的一个方法
-
目标(target):被通知对象,下文中的UserServiceImpl类的对象
-
代理(proxy):向目标对象加入通知创建的新对象
-
切入点(pointcut):切面通知执行的“地点”的定义
-
连接点(jointpoint):与切入点匹配的执行点
环境搭建:
<dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency></dependencies>
beans.xml
<aop:aspectj-autoproxy/>
Service接口
public interface Servic { void add(); void delete(); void update(); void select();}
ServiceImpl类
public class ServiceImpl implements Servic{ @Override public void add() { System.out.println("增加了一个用户"); } @Override public void delete() { System.out.println("删除了一个用户"); } @Override public void update() { System.out.println("更新了一个用户"); } @Override public void select() { System.out.println("查询了一个用户"); }}
10.1、使用Spring API接口实现
需要继承Spring提供的AOP接口【AfterReturningAdvice、MethodBeforeAdvice】
<!--aop配置--><aop:config> <!--要切的类--> <aop:pointcut id="poincut" expression="execution(* com.stjp.Service.ServiceImpl.*(..))"/> <!--用什么方法切,切到哪里--> <aop:advisor advice-ref="logafter" pointcut-ref="poincut"/> <aop:advisor advice-ref="logabefore" pointcut-ref="poincut"/></aop:config>
after类
public class logAfter implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println(method.getName()+o);
}
}
before类
public class logBefore implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+method.getName()+"执行前");
}
}
10.2、使用自定义类实现
<aop:config>
<!-- 自定义切面-->
<aop:aspect id="diy" ref="afterorbefore">
<!-- 要切的类-->
<aop:pointcut id="poincut" expression="execution(* com.stjp.Service.ServiceImpl.*(..))"/>
<!--切的方式-->
<aop:after method="after" pointcut-ref="poincut"/>
<aop:before method="before" pointcut-ref="poincut"/>
</aop:aspect>
</aop:config>
自定义类
public class afterOrBefore {
public void before(){
System.out.println("使用方法前");
}
public void after(){
System.out.println("使用方法后");
}
}
10.3、使用注解实现
@Aspect//说明这是一个切面
public class afterOrBefore {
@Before("execution(* com.stjp.Service.ServiceImpl.*(..))")
public void before(){
System.out.println("使用方法前");
}
@After("execution(* com.stjp.Service.ServiceImpl.*(..))")
public void after(){
System.out.println("使用方法后");
}
}
11、Mybatis和Spring整合
文档: https://mybatis.org/spring/zh/
- 整合核心就是把Mybatis中的sqlSessionFactory和sqlSession交给Spring管理
- 可以使得Service层更加灵活!!!
环境配置
<dependencies>
<!--JDBC-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--mybatis -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--Spring-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
<!--AOP-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
Spring-Mybatis.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">
<!--DataSource:使用Spring的数据源DriverManagerDataSource代替MyBatis的配置-->
<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/mybatis?useUnicode=true&characterEncoding=UTF-8&useSSL=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--绑定Mybatis配置文件-->
<property name="configLocation" value="classpath:mybatisConfig.xml"/>
</bean>
<!--SqlSessionTemplate就是我们使用的SQLSession-->
<bean id="sqlSesion" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
方法一:
userMapperImpl类【实际上是service层】
public class userMapperImpl implements userMapper{
private SqlSessionTemplate SqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
SqlSession = sqlSession;
}
@Override
public List<user> getUSer() {
userMapper mapper = SqlSession.getMapper(userMapper.class);
List<user> list = mapper.getUSer();
return list;
}
}
**方法二:**使用SqlSessionDaoSupport
userMapperImpl类【实际上是service层】
public class userMApperImpl2 extends SqlSessionDaoSupport implements userMapper{
@Override
public List<user> getUSer() {
return getSqlSession().getMapper(userMapper.class).getUSer();
}
}
Spring容器上注册bean
<bean id="userMapper2" class="com.stjp.Mapper.userMApperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
12、Spring声明式事务
12.1、回顾事务
- 把一组业务当成一个业务来做,要么都完成,要么都失败
- 确保完整性和一致性
事务的ACID原则:
- 一致性
- 原子性
- 隔离性
- 持久性
12.2、Spring中的事务管理
- 声明式事务管理:AOP
- 编程式事务管理
第一步:
<!--声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="datasource" />
</bean>
第二步:
<!--结合aop实现事务置入-->
<!--配置事务的类-->
<tx:advice id="tx1" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--配置事务的传播特性-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txpointxut" expression="execution(* com.mapper.*.*(..))"/>
<aop:advisor advice-ref="tx1" pointcut-ref="txpointxut"/>
</aop:config>
注意:动态代理代理的是接口!!!!