文章目录
Spring5
- Spring是一个开源的免费的框架(容器)
- Spring是一个轻量级的、非入侵式的框架
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
IOC理论推导
传统方式:
- UserDao接口
package com.sgl.dao;
public interface UserDao {
void getUser();
}
- UserDaoImpl、UserMysqlImpl、UserOracleImpl实现类
package com.sgl.dao;
public class UserDaoImpl implements UserDao{
@Override
public void getUser() {
System.out.println("默认获取用户数据");
}
}
package com.sgl.dao;
public class UserMysqlImpl implements UserDao{
@Override
public void getUser() {
System.out.println("Mysql获取用户数据");
}
}
package com.sgl.dao;
public class UserOracleImpl implements UserDao{
@Override
public void getUser() {
System.out.println("Oracle获取用户数据");
}
}
- UserService业务接口
package com.sgl.service;
public interface UserService {
void getUser();
}
- UserServiceImpl业务实现
package com.sgl.service;
import com.sgl.dao.UserDao;
import com.sgl.dao.UserDaoImpl;
import com.sgl.dao.UserMysqlImpl;
import com.sgl.dao.UserOracleImpl;
public class UserServiceImpl implements UserService{
//只能一个一个实现
private UserDao userDao = new UserDaoImpl();
//private UserDao userDao = new UserMysqlImpl();
//private UserDao userDao = new UserOracleImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
测试:
import com.sgl.service.UserService;
import com.sgl.service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是业务层,dao层不需要解除
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
/*
结果:
默认获取用户数据 UserServiceImpl业务对应的是 private UserDao userDao = new UserDaoImpl();
Mysql获取用户数据 UserServiceImpl业务对应的是 private UserDao userDao = new UserMysqlImpl();
Oracle获取用户数据 UserServiceImpl业务对应的是 private UserDao userDao = new UserOracleImpl();
*/
IOC理论原型:
利用set进行动态实现的注入 修改UserServiceImpl如下:
- UserServiceImpl业务实现
package com.sgl.service;
import com.sgl.dao.UserDao;
public class UserServiceImpl implements UserService{
private UserDao userDao;
//利用set进行动态实现的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
测试:
import com.sgl.dao.UserDaoImpl;
import com.sgl.dao.UserMysqlImpl;
import com.sgl.dao.UserOracleImpl;
import com.sgl.service.UserService;
import com.sgl.service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是业务层,dao层不需要解除
UserService userService = new UserServiceImpl();
((UserServiceImpl) userService).setUserDao(new UserDaoImpl());
//((UserServiceImpl) userService).setUserDao(new UserMysqlImpl());
//((UserServiceImpl) userService).setUserDao(new UserOracleImpl());
userService.getUser();
}
}
结果:
/*
结果:
默认获取用户数据 ---> ((UserServiceImpl) userService).setUserDao(new UserDaoImpl());
Mysql获取用户数据 ---> ((UserServiceImpl) userService).setUserDao(new UserMysqlImpl());
Oracle获取用户数据 ---> ((UserServiceImpl) userService).setUserDao(new UserOracleImpl());
*/
小结:
- 传统方式:程序是主动创建对象,控制权在程序员!!
- IOC理论原型(set注入后):程序员不在具有主动性,变成了被动接受对象
- ((UserServiceImpl) userService).setUserDao(new UserDaoImpl()) 为什么要强转?—> 因为实现的接口没有set方法,实现类独有的方法
IOC
控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法
- 实体类
package com.sgl.pojo;
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
- 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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用Spring来创建对象,在Spring这些都称为Bean
类型 变量名 = new 类型();
Hello hello = new Hello();
id = 变量名
class = new 的对象
property 相当于给对象中的属性设置一个值
-->
<bean id="hello" class="com.sgl.pojo.Hello">
<property name="str" value="Spring"/>
</bean>
</beans>
测试:
import com.sgl.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取Spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//现在对象都在Spring中管理,直接取出即可
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
/*
结果: Hello{str='Spring'}
*/
User案例再改进:
- UserDao接口
package com.sgl.dao;
public interface UserDao {
void getUser();
}
- UserDaoImpl、UserMysqlImpl、UserOracleImpl实现类
package com.sgl.dao;
public class UserDaoImpl implements UserDao{
@Override
public void getUser() {
System.out.println("默认获取用户数据");
}
}
package com.sgl.dao;
public class UserMysqlImpl implements UserDao{
@Override
public void getUser() {
System.out.println("Mysql获取用户数据");
}
}
package com.sgl.dao;
public class UserOracleImpl implements UserDao{
@Override
public void getUser() {
System.out.println("Oracle获取用户数据");
}
}
- UserService业务接口
package com.sgl.service;
public interface UserService {
void getUser();
}
- UserServiceImpl业务实现
package com.sgl.service;
import com.sgl.dao.UserDao;
public class UserServiceImpl implements UserService{
private UserDao userDao;
//利用set进行动态实现的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
- 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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDaoImpl" class="com.sgl.dao.UserDaoImpl"/>
<bean id="mysqlImpl" class="com.sgl.dao.UserMysqlImpl"/>
<bean id="oracleImpl" class="com.sgl.dao.UserOracleImpl"/>
<bean id="userServiceImpl" class="com.sgl.service.UserServiceImpl">
<property name="userDao" ref="userDaoImpl"/>
</bean>
<!--
ref:引用Spring容器中创建好的对象
value:具体的值,基本数据类型
-->
</beans>
测试:
import com.sgl.service.UserServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void Test(){
//获取ApplicationContext:拿到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl userService = (UserServiceImpl) context.getBean("userServiceImpl");
userService.getUser();
}
}
结果:
/*
结果:
默认获取用户数据 ---> <bean id="userService" class="com.sgl.service.UserServiceImpl">
<property name="userDao" ref="userDaoImpl"/>
</bean>
Mysql获取用户数据 ---> <bean id="userService" class="com.sgl.service.UserServiceImpl">
<property name="userDao" ref="mysqlImpl"/>
</bean>
Oracle获取用户数据 ---> <bean id="userService" class="com.sgl.service.UserServiceImpl">
<property name="userDao" ref="oracleImpl"/>
</bean>
*/
控制反转:
- 反转:程序本身不创建对象,而变成被动的接收对象
- 依赖注入:就是利用set方法来进行注入
- IOC是一种编程思想,由主动的编程编程被动的接收
- 可以通过newClassPathXmlApplicationContext去浏览以下底层代码
要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IOC:对象由Spring创建,管理,装配
IOC创建对象的方式
实体类:
package com.sgl.pojo;
public class User {
private String name;
// public User() {
// System.out.println("User的无参构造");
// }
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.sgl.pojo.User">
<property name="name" value="刚龙"/>
</bean>
</beans>
测试:
import com.sgl.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.show();
}
}
-
使用无参构造创建对象,默认
-
使用有参构造创建对象:
- 下标赋值
<!--第一种:下标赋值--> <bean id="user" class="com.sgl.pojo.User"> <constructor-arg index="0" value="狂神"/> </bean>
- 类型创建
<!--第二种:通过类型创建(不建议使用)--> <bean id="user" class="com.sgl.pojo.User"> <constructor-arg type="java.lang.String" value="倩倩"/> </bean>
- 直接通过参数名
<!--第三种:直接通过参数名来设置--> <bean id="user" class="com.sgl.pojo.User"> <constructor-arg name="name" value="老憨"/> </bean>
总结:在配置文件加载的时候,容器中管理的对象就已经实例化了
Spring配置说明
实体类是上面的User
别名alias
<alias name="user" alias="helloUser"/>
测试:
import com.sgl.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//可以用user可以用helloUser
User user = (User) context.getBean("helloUser");
user.show();
}
}
Bean的配置
实体类Teacher
package com.sgl.pojo;
public class Teacher {
private String name;
public Teacher() {
System.out.println("Teacher的无参构造");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+name);
}
}
<!--
id:bean 的唯一标识符,相当于我们学习的对象名
class: bean 对象所对应的全限定名 包名+类型
name: 也是别名,并且name可以取多个别名,可以用不同的分隔符
-->
<bean id="teacher" class="com.sgl.pojo.Teacher" name="t1 t2,t3;t4">
<property name="name" value="秦疆"/>
</bean>
测试:
import com.sgl.pojo.Teacher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//teacher可以换成t1/t2/t3/t4
Teacher teacher = (Teacher) context.getBean("teacher");
teacher.show();
}
}
/*结果:
Teacher的无参构造
name=秦疆
*/
import
一般用于团队的开发使用,它可以将多个配置文件导入合并为一个,如:
项目有多人开发,这三个复制不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!
applicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="beans.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>
</beans>
使用的时候直接使用总的配置就可
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
依赖注入
构造器注入
IOC创建对象的方式已讲解
Set方式注入 ***
- 依赖注入:Set注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,由容器来注入
环境搭建
- 复杂类型Address
package com.sgl.pojo;
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
- 真实测试对象Student
package com.sgl.pojo;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class Student {
private String name;
private Address address; //复杂类型
private String[] books;
private List<String> hobbies;
private Map<String,String> card;
private Set<String> games;
private String girlfriend;
private Properties info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public String getGirlfriend() {
return girlfriend;
}
public void setGirlfriend(String girlfriend) {
this.girlfriend = girlfriend;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{ \n " +
"name='" + name + '\'' +
", \n address=" + address.toString() +
", \n books=" + Arrays.toString(books) +
", \n hobbies=" + hobbies +
", \n card=" + card +
", \n games=" + games +
", \n girlfriend='" + girlfriend + '\'' +
", \n info=" + info + "\n" +
'}';
}
}
- 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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--第一种:普通值注入,value-->
<bean id="student" class="com.sgl.pojo.Student">
<property name="name" value="狂神"/>
</bean>
</beans>
测试:
import com.sgl.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.getName());
}
}
完善注入信息
<?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">
<bean id="address" class="com.sgl.pojo.Address">
<property name="address" value="河南"/>
</bean>
<bean id="student" class="com.sgl.pojo.Student">
<!--第一种:普通值注入,value-->
<property name="name" value="狂神"/>
<!--第二种:Bean注入,ref-->
<property name="address" ref="address"/>
<!--数组-->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>三国演义</value>
<value>水浒传</value>
</array>
</property>
<!--List-->
<property name="hobbies">
<list>
<value>听歌</value>
<value>打游戏</value>
<value>散步</value>
</list>
</property>
<!--Map-->
<property name="card">
<map>
<entry key="身份证" value="4115262000xxxxxx"/>
<entry key="银行卡" value="1516551656515616"/>
</map>
</property>
<!--Set-->
<property name="games">
<set>
<value>LOL</value>
<value>CF</value>
<value>CSGO</value>
</set>
</property>
<!--null-->
<property name="girlfriend">
<null></null>
</property>
<!--Properties-->
<property name="info">
<props>
<prop key="driver">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=ture&characterEncoding=UTF-8</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
测试:
import com.sgl.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());
}
}
结果:
/*
Student{
name='狂神',
address=Address{address='河南'},
books=[红楼梦, 西游记, 三国演义, 水浒传],
hobbies=[听歌, 打游戏, 散步],
card={身份证=4115262000xxxxxx, 银行卡=1516551656515616},
games=[LOL, CF, CSGO],
girlfriend='null',
info={password=123456, url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=ture&characterEncoding=UTF-8, driver=com.mysql.jdbc.Driver, username=root}
}
*/
拓展方式注入
使用p命令空间和c命令空间进行注入
- 实体类
package com.sgl.pojo;
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- userbeans.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"
//使用p、c要加入以下两行内容
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.sgl.pojo.User" p:age="22" p:name="刚龙"/>
<bean id="user2" class="com.sgl.pojo.User" c:age="24" c:name="倩倩"/>
</beans>
- 测试
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
//在其后加上User.class就不需要强转了
User user = context.getBean("user", User.class);
System.out.println(user.toString());
}
注意点:
p命名空间和c命名空间不能直接使用,需要导入xml约束
<!--p命名空间注入,可以直接注入属性的值:property-->
xmlns:p="http://www.springframework.org/schema/p"
<!--c命名空间注入,通过构造器注入:construct-args-->
xmlns:c="http://www.springframework.org/schema/c"
Bean的作用域
作用域 | 描述 |
---|---|
singleton | (默认)将每个 Spring IoC 容器的单个 bean 定义范围限定为单个对象实例。 |
prototype | 将单个 bean 定义的作用域限定为任意数量的对象实例。 |
request | 将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有一个在单个 bean 定义后面创建的 bean 实例。仅在可感知网络的 Spring ApplicationContext 中有效。 |
session | 将单个 bean 定义的范围限定为 HTTP Session 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
application | 将单个 bean 定义的范围限定为ServletContext 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
websocket | 将单个 bean 定义的范围限定为WebSocket 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
- 单例模式(Spring默认机制)
<bean id="user" class="com.sgl.pojo.User" c:age="24" c:name="倩倩"
scope="singleton"/>
- 原型模式:每次从容器中get的时候,都会产生一个新对象
<bean id="user" class="com.sgl.pojo.User" p:age="22" p:name="刚龙" scope="prototype"/>
测试:
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user", User.class);
User user1 = context.getBean("user", User.class);
System.out.println(user.hashCode());
System.out.println(user1.hashCode());
System.out.println(user==user1);
}
/*单例模式结果:
1561408618
1561408618
true
*/
/*原型模式结果:
2050404090
388043093
false
*/
- request、session、application、websocket只能在Web开发中使用到
Bean的自动装配
- 自动装配是Spring满足bean依赖的一种方式
- Spring会在上下文中自动寻找,并会自动给bean装配属性
Spring有三种装配方式:
- 在xml中显示的装配
- 在java中显示装配
- 隐式的自动装配bean ***
xml中显示的装配
- 实体类
package com.sgl.pojo;
public class Cat {
public void shout(){
System.out.println("喵喵~~~~~");
}
}
package com.sgl.pojo;
public class Dog {
public void shout(){
System.out.println("汪汪~~~~~");
}
}
package com.sgl.pojo;
public class People {
private Cat cat;
private Dog dog;
private String name;
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", 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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.sgl.pojo.Cat"/>
<bean id="dog" class="com.sgl.pojo.Dog"/>
<bean id="people" class="com.sgl.pojo.People">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="name" value="刚龙"/>
</bean>
</beans>
测试:
import com.sgl.pojo.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people", People.class);
people.getDog().shout();
people.getCat().shout();
}
}
/*结果:
汪汪~~~~~
喵喵~~~~~
*/
隐式的自动装配bean ***
byName自动装配
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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.sgl.pojo.Cat"/>
<bean id="dog" class="com.sgl.pojo.Dog"/>
<!--byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应 bean id-->
<bean id="people" class="com.sgl.pojo.People" autowire="byName">
<property name="name" value="刚龙"/>
</bean>
</beans>
测试:
import com.sgl.pojo.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people", People.class);
people.getDog().shout();
people.getCat().shout();
}
}
/*结果:
汪汪~~~~~
喵喵~~~~~
*/
byType自动装配
<?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">
<bean class="com.sgl.pojo.Cat"/>
<bean class="com.sgl.pojo.Dog"/>
<!--byType:会自动在容器上下文中查找,和自己对象的属性类型相同的bean-->
<bean id="people" class="com.sgl.pojo.People" autowire="byType">
<property name="name" value="刚龙"/>
</bean>
</beans>
测试:
import com.sgl.pojo.Cat;
import com.sgl.pojo.Dog;
import com.sgl.pojo.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people", People.class);
Dog dog = people.getDog();
Cat cat = people.getCat();
dog.shout();
cat.shout();
}
}
/*结果:
汪汪~~~~~
喵喵~~~~~
*/
小结:
- byName:需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
- byType:需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性一致
- byName就是通过Bean的id或者name,byType就是按Bean的Class的类型
注解实现自动装配
- 导入约束(context约束)
xmlns:context="http://www.springframework.org/schema/context"
- 配置注解的支持:context:annotation-config/ ***
<?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>
@Autowired注解
直接在属性上使用即可!也可以在set方式上使用!
使用**@Autowired可以不用编写set方法,前提是这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byType**
测试:
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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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">
<context:annotation-config/>
<bean id="cat" class="com.sgl.pojo.Cat"/>
<bean id="dog" class="com.sgl.pojo.Dog"/>
<bean id="people" class="com.sgl.pojo.People"/>
</beans>
实体类(方式一):
package com.sgl.pojo;
import org.springframework.beans.factory.annotation.Autowired;
public class People {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
}
实体类(方式二):
如果@Autowired自动装配比较复杂,自动装配无法通过一个注解 @Autowired 完成时,可以使用**@Qualifier(value=“xxx”)去配和@Autowired的使用,指定一个唯一的bean对象注入,如beans.xml**
<bean id="cat22" class="com.sgl.pojo.Cat"/>
<bean id="cat11" class="com.sgl.pojo.Cat"/>
<bean id="dog22" class="com.sgl.pojo.Dog"/>
<bean id="dog11" class="com.sgl.pojo.Dog"/>
<bean id="people" class="com.sgl.pojo.People"/>
如果不配合@Qualifier使用会报错(因为没有cat只有cat11和cat22)
package com.sgl.pojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class People {
@Autowired
@Qualifier(value = "cat11")
private Cat cat;
@Autowired
@Qualifier(value = "dog11")
private Dog dog;
}
@Resource注解
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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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">
<context:annotation-config/>
<bean id="cat" class="com.sgl.pojo.Cat"/>
<bean id="dog" class="com.sgl.pojo.Dog"/>
<bean id="people" class="com.sgl.pojo.People"/>
</beans>
实体类(方式一):
package com.sgl.pojo;
import org.springframework.beans.factory.annotation.Autowired;
public class People {
@Resource
private Cat cat;
@Resource
private Dog dog;
private String name;
}
实体类(方式二):
<bean id="cat22" class="com.sgl.pojo.Cat"/>
<bean id="cat11" class="com.sgl.pojo.Cat"/>
<bean id="dog22" class="com.sgl.pojo.Dog"/>
<bean id="dog11" class="com.sgl.pojo.Dog"/>
<bean id="people" class="com.sgl.pojo.People"/>
如果不给@Resource加参数name=“xxx”,就会报错(No qualifying bean of type ‘com.sgl.pojo.Cat’ available: expected single matching bean but found 2: cat22,cat11)
package com.sgl.pojo;
import javax.annotation.Resource;
public class People {
@Resource(name = "cat11")
private Cat cat;
@Resource(name = "dog11")
private Dog dog;
private String name;
}
测试:(都可以成功)
import com.sgl.pojo.Cat;
import com.sgl.pojo.Dog;
import com.sgl.pojo.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people", People.class);
Dog dog = people.getDog();
Cat cat = people.getCat();
dog.shout();
cat.shout();
}
}
小结:
@Autowired 和@Resource的区别:
-
@Autowired 通过byType的方式实现,而且必须要求这个对象存在***
-
@Resource 通过**byName的方式实现,如果找不到名字,则可以通过byType实现!**如果两个都找不到的情况,直接报错
-
执行顺序不同:@Autowired通过byType的方式实现,@Resource通过byName的方式实现
Spring注解开发
需要保证aop的包导入
需要导入context约束,增加注解的支持
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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">
<context:annotation-config/>
</beans>
@Component
-
bean
-
属性如何注入
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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">
<context:annotation-config/>
<!--指定扫描的包。这个包下的注解就会生效-->
<context:component-scan base-package="com.sgl.pojo"/>
</beans>
package com.sgl.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//@Component:组件,放在类上,说明这个类被spring管理了,就是bean!
//@Component 等价于 <bean id="user" class="com.sgl.pojo.User"/>
@Component
public class User {
//@Value("刚龙") 相当于 <property name="name" value="刚龙"/>
@Value("刚龙")
public String name;
//@Value("刚龙")
public void setName(String name) {
this.name = name;
}
}
- 衍生的注解
@Component的衍生注解,在Web开发中,会按照mvc三层架构分层
- dao 【@Repository】
- service 【@Service】
- controller 【@Controller】
这四个注解功能都是一样,都是代表将某个类注册到Spring中,装配Bean
修改applicationContext.xml
<!--指定扫描的包。这个包下的注解就会生效-->
<context:component-scan base-package="com.sgl"/>
- 自动装配
@Autowired
@Resource
@Nullable 字段被标记这个注解,说明这个字段可以为null
@Resource
- 作用域
@Scope("singleton") 单例模式
@Scope("prototype") 原型模式
package com.sgl.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
//@Component:组件,放在类上,说明这个类被spring管理了,就是bean!
//@Component 等价于 <bean id="user" class="com.sgl.pojo.User"/>
@Component
//@Scope("singleton") 单例 @Scope("prototype") 原型
@Scope("prototype")
public class User {
//@Value("刚龙") 相当于 <property name="name" value="刚龙"/>
@Value("刚龙")
public String name;
//@Value("刚龙")
public void setName(String name) {
this.name = name;
}
}
小结:
xml与注解:
- xml更加万能,适合于任何场所,维护比较简单
- 注解 不是自己的类使用不了,维护更佳复杂
一般xml用来管理Bean,注解负责完成属性的注入
注意:
- 必须让注解生效,需要开启注解的支持
Java配置Spring
多看注释
实体类
package com.sgl.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//@Component:组件,放在类上,说明这个类被spring管理了,就是bean!
//@Component 等价于 <bean id="user" class="com.sgl.pojo.User"/>
@Component
public class User {
private String name;
public String getName() {
return name;
}
//@Value("刚龙") 相当于 <property name="name" value="刚龙"/>
@Value("刚龙")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
package com.sgl.config;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SglConfig2 {
}
配置文件
package com.sgl.config;
import com.sgl.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//@Configuration Spring容器托管,注册到容器中,本身就是一个@Configuration
//@Configuration 代表这是一个配置类,相当于beans.xml一样
@Configuration
@ComponentScan("com.sgl.pojo")
@Import(SglConfig2.class) //引用
public class SglConfig {
//注册一个bean,相当于我们之前写的一个bean标签
//这个方法的名字,相当于bean标签中的id属性
//这个方法的返回值,相当于bean标签中的class属性
@Bean
public User getUser() {
return new User();
}
// @Bean
// public User user() {
// return new User();
// }
}
@Import(SglConfig2.class) //引用
package com.sgl.config;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SglConfig2 {
}
测试:
import com.sgl.config.SglConfig;
import com.sgl.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest {
public static void main(String[] args) {
//使用配置类方式,只能通过AnnotationConfigApplicationContext 上下文获取容器,通过配置类的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(SglConfig.class);
User user = context.getBean("getUser", User.class);
//User user = context.getBean("user", User.class);
System.out.println(user.getName());
}
}
代理模式
静态代理模式
角色分析:
- 抽象角色:一般使用接口或者抽象类解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作
- 客户:访问代理角色的人
案例一:
代码步骤:
- 接口
package com.sgl.demo;
//租房
public interface Rent {
public void rent();
}
- 真实角色
package com.sgl.demo;
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东出租房子");
}
}
- 代理角色
package com.sgl.demo;
public class Proxy implements Rent{
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seeHouse();
host.rent();
contract();
fare();
}
//看房
public void seeHouse(){
System.out.println("中介带你看房");
}
//签合同
public void contract(){
System.out.println("前租赁合同");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
- 客户端访问代理角色
package com.sgl.demo;
public class Client {
public static void main(String[] args) {
//房东要出租房子
Host host = new Host();
//代理,中介帮房东租房子 但是代理角色会有有些附属操作
Proxy proxy = new Proxy(host);
//不用找房东,直接找中介租房
proxy.rent();
}
}
再理解,案例二:
- 接口
package com.sgl.demo02;
//接口
public interface UserService {
void add();
void delete();
void update();
void query();
}
- 真实角色
package com.sgl.demo02;
//真实角色
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加一个用户");
}
@Override
public void delete() {
System.out.println("删除一个用户");
}
@Override
public void update() {
System.out.println("修改一个用户");
}
@Override
public void query() {
System.out.println("查询一个用户");
}
}
- 代理角色
package com.sgl.demo02;
//代理角色
public class UserServiceProxy implements UserService{
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
@Override
public void add() {
log("add");
userService.add();
}
@Override
public void delete() {
log("delete");
userService.delete();
}
@Override
public void update() {
log("update");
userService.update();
}
@Override
public void query() {
log("query");
userService.query();
}
//日志方法
public void log(String msg){
System.out.println("[debug] 使用了"+msg+"方法");
}
}
- 客户端访问代理角色
package com.sgl.demo02;
//客户端访问代理角色
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);
proxy.add();
}
}
动态代理模式
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口:JDK动态代理
- 基于类:cglib
- Java字节码实现:javasist
了解两个类:Proxy:代理 InvocationHandler:调用处理程序
代理:
package com.sgl.demo03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//用这个类,自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是使用反射机制
seeHouse();
Object invoke = method.invoke(rent, args);
fare();
return invoke;
}
public void seeHouse(){
System.out.println("中介带你看房子");
}
public void fare(){
System.out.println("收中介费");
}
}
客户端:
package com.sgl.demo03;
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色:现在没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们调用的接口对象
pih.setRent(host);
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
代理:
package com.sgl.demo04;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//用这个类,自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
//动态代理的本质,就是使用反射机制
Object invoke = method.invoke(target, args);
return invoke;
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
客户端:
package com.sgl.demo04;
import com.sgl.demo02.UserService;
import com.sgl.demo02.UserServiceImpl;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色:不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置要代理的对象
pih.setTarget(userService);
//动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.add();
}
}
AOP(面向切面编程)
AOP在Spring中的作用
提供声明事务;允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
- 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 “地点”的定义。
- 连接点(JointPoint):与切入点匹配的执行点。
Spring AOP 默认为 AOP 代理使用标准的 JDK 动态代理。这允许代理任何接口(或接口集)
Spring实现AOP
使用AOP织入,需要导入一个依赖包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
方式一:使用原生Spring API接口
UserSevice
package com.sgl.service;
public interface UserService {
void add();
void delete();
void update();
void select();
}
UserServiceImpl
package com.sgl.service;
public class UserServiceImpl implements UserService{
@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("查询一个用户");
}
}
Log
package com.sgl.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
//method:要执行的目标对象的方法
//args:参数
//target:目标对象
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+target.getClass().getName()+"的"+method.getName()+"方法");
}
}
AfterLog
package com.sgl.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回结果为"+returnValue);
}
}
applicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.sgl.service.UserServiceImpl"/>
<bean id="log" class="com.sgl.log.Log"/>
<bean id="afterLog" class="com.sgl.log.AfterLog"/>
<!--方式一:使用原生Spring API接口-->
<!--配置aop:需要导入aop依赖-->
<aop:config>
<!--切入点:expression:表达式,execution(要执行的位置! * * * * * *)-->
<aop:pointcut id="pointcut" expression="execution(* com.sgl.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加!-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
测试:
import com.sgl.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//注意:动态代理,代理的是接口
UserService userService = context.getBean("userService", UserService.class);
userService.delete();
}
}
结果:
执行了com.sgl.service.UserServiceImpl的delete方法
删除一个用户
执行了delete方法,返回结果为null
方式二:自定义实现AOP【主要是切面定义】
UserSevice
package com.sgl.service;
public interface UserService {
void add();
void delete();
void update();
void select();
}
UserServiceImpl
package com.sgl.service;
public class UserServiceImpl implements UserService{
@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("查询一个用户");
}
}
DiyPointCut
package com.sgl.diy;
public class DiyPointCut {
public void before(){
System.out.println("========执行前=========");
}
public void after(){
System.out.println("========执行后=========");
}
}
applicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.sgl.service.UserServiceImpl"/>
<bean id="log" class="com.sgl.log.Log"/>
<bean id="afterLog" class="com.sgl.log.AfterLog"/>
<!--方式二:自定义类-->
<bean id="diy" class="com.sgl.diy.DiyPointCut"/>
<aop:config>
<!--自定义切面,ref:要引用的类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.sgl.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
测试:
import com.sgl.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//注意:动态代理,代理的是接口
UserService userService = context.getBean("userService", UserService.class);
userService.delete();
}
}
结果:
========执行前=========
删除一个用户
========执行后=========
方式三:使用注解实现AOP
UserSevice
package com.sgl.service;
public interface UserService {
void add();
void delete();
void update();
void select();
}
UserServiceImpl
package com.sgl.service;
public class UserServiceImpl implements UserService{
@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("查询一个用户");
}
}
AnnotationPointCut
package com.sgl.diy;
//方式三:使用注解实现AOP
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect //标注这个类是一个切面
public class AnnotationPointCut {
@Before("execution(* com.sgl.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("=========方法执行前========");
}
@After("execution(* com.sgl.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("=========方法执行后========");
}
//在环绕中增强,给定一个参数,代表我们要处理切入的点
@Around("execution(* com.sgl.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前");
//获得签名
System.out.println("signature:"+joinPoint.getSignature());
//执行方法
Object proceed = joinPoint.proceed();
System.out.println("环绕后");
}
}
applicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.sgl.service.UserServiceImpl"/>
<bean id="log" class="com.sgl.log.Log"/>
<bean id="afterLog" class="com.sgl.log.AfterLog"/>
<!--方式三:注解实现AOP-->
<bean id="annotationPointCut" class="com.sgl.diy.AnnotationPointCut"/>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>
</beans>
测试:
import com.sgl.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//注意:动态代理,代理的是接口
UserService userService = context.getBean("userService", UserService.class);
userService.delete();
}
}
结果:
环绕前
signature:void com.sgl.service.UserService.delete()
=========方法执行前========
删除一个用户
=========方法执行后========
环绕后
整合Mybatis
回顾Mybatis
- 编写实体类
- 编写核心配置文件
- 编写接口
- 编写Mapper.xml文件
- 测试
导入依赖
pom.xml
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.12</version>
</dependency>
<!--Spring操作数据库需要spring-jdbc-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
- 实体类
package com.sgl.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
- Dao接口
package com.sgl.mapper;
import com.sgl.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> getUserList();
}
- 核心配置文件
mybatis-config.xml
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
<typeAliases>
<typeAlias type="com.sgl.pojo.User"/>
</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/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.sgl.mapper.UserMapper"/>
</mappers>
</configuration>
- 接口实现类 由原来的UserDaoImpl转换为Mapper配置文件
UserMapper.xml
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.sgl.mapper.UserMapper">
<!--select查询语句-->
<select id="getUserList" resultType="user">
select * from mybatis.user
</select>
</mapper>
- 测试
import com.sgl.mapper.UserMapper;
import com.sgl.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyTest {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
}
结果:
User(id=1, name=刚龙, pwd=123456)
User(id=2, name=倩倩, pwd=123456)
User(id=3, name=肖总, pwd=123456)
问题解决:
- 资源导出失败的问题:在pom.xml中添加
<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
- 1 字节的 UTF-8 序列的字节 1 无效
将xml文件的UTF-8修改为UTF8
如果遇到像这样的字节错误,修改xml文件,UTF-8改为UTF8
Mybatis-Spring 一
- 实体类 User
- 接口 UserDao
- UserMapper.xml
- 增加一个实现类 UserMapperImpl
package com.sgl.mapper;
import com.sgl.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper{
//之前使用sqlSession执行,现在使用SqlSessionTempLate
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> getUserList() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
return userList;
}
}
- mybatis-config.xml (只做两件事:别名和设置)
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
<!--设置-->
<!--<settings>-->
<!-- <setting name="" value=""/>-->
<!--</settings>-->
<typeAliases>
<typeAlias type="com.sgl.pojo.User"/>
</typeAliases>
</configuration>
- spring-dao.xml 【重要】
<?xml version="1.0" encoding="UTF8"?>
<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:aop="http://www.springframework.org/schema/aop"
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">
<!--Datasource:使用spring的数据源替换Mybatis的配置
使用spring提供的JDBC: org.springframework.jdbc.datasource.DriverManagerDataSource
-->
<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?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<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:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/sgl/mapper/*.xml"/>
</bean>
<!--SqlSessionTemplate就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入sqlSessionFactory,因为没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
- applicationContext.xml
<?xml version="1.0" encoding="UTF8"?>
<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:aop="http://www.springframework.org/schema/aop"
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">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.sgl.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
测试:
import com.sgl.mapper.UserMapper;
import com.sgl.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
import java.util.List;
public class MyTest {
public static void main(String[] args) throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
List<User> userList = userMapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
}
Mybatis-Spring 二
- UserMapperImpl2
package com.sgl.mapper;
import com.sgl.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
@Override
public List<User> getUserList() {
// SqlSession sqlSession = getSqlSession();
// UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// List<User> userList = mapper.getUserList();
// return userList;
return getSqlSession().getMapper(UserMapper.class).getUserList();
}
}
- applicationContext.xml
<?xml version="1.0" encoding="UTF8"?>
<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:aop="http://www.springframework.org/schema/aop"
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">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.sgl.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
<bean id="userMapper2" class="com.sgl.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
测试:
import com.sgl.mapper.UserMapper;
import com.sgl.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
import java.util.List;
public class MyTest {
public static void main(String[] args) throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
List<User> userList = userMapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
@Test
public void test () {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
List<User> userList = userMapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
}
注意:使用SqlSessionDaoSupport获取sqlSession不需要注入
声明事务
回顾事务
- 要么都成功,要么都失败
- 确保完整性和一致性
事务ACID原则:
- 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 - 一致性(Consistency)
事务前后数据的完整性必须保持一致。 - 隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。 - 持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
spring中的事务管理
添加约束:
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
- UserMapper
package com.sgl.mapper;
import com.sgl.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserMapper {
List<User> getUserList();
//添加一个用户
int addUser(User user);
//删除一个用户
int deleteUser(@Param("id") int id);
}
- UserMapper.xml
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.sgl.mapper.UserMapper">
<!--select查询语句-->
<select id="getUserList" resultType="user">
select * from mybatis.user;
</select>
<insert id="addUser" parameterType="user">
insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd});
</insert>
<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id=#{id};
</delete>
</mapper>
- UserMapperImpl
package com.sgl.mapper;
import com.sgl.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
@Override
public List<User> getUserList() {
User user = new User(7,"孙悟空","777777");
//SqlSession sqlSession = getSqlSession();
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
mapper.addUser(user);
mapper.deleteUser(5);
//List<User> userList = mapper.getUserList();
return mapper.getUserList();
}
@Override
public int addUser(User user) {
return getSqlSession().getMapper(UserMapper.class).addUser(user);
}
@Override
public int deleteUser(int id) {
return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
}
}
- spring-dao.xml
<?xml version="1.0" encoding="UTF8"?>
<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:aop="http://www.springframework.org/schema/aop"
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">
<!--Datasource:使用spring的数据源替换Mybatis的配置
使用spring提供的JDBC: org.springframework.jdbc.datasource.DriverManagerDataSource
-->
<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?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<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:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/sgl/mapper/*.xml"/>
</bean>
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg name="dataSource" ref="dataSource" />
</bean>
<!--结合AOP实现事务的织入-->
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给方法配置事务-->
<!--给事务配置传播特性 propagation="REQUIRED"默认 propagation:传播-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务织入-->
<aop:config>
<!--execution(* com.sgl.service.UserServiceImpl.*(..))"-->
<aop:pointcut id="txPointCut" expression="execution(* com.sgl.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
测试:
import com.sgl.mapper.UserMapper;
import com.sgl.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper",UserMapper.class);
List<User> userList = userMapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
}
小结:
- 如果不添加事务,即使代码出错,也会插入数据
- 添加spring事务后,直接失败