Spring AOP
代理模式
- 为什么要学习代理模式呢
- Spring AOP的底层是代理模式
- 代理模式的分类
- 静态代理
- 动态代理
一、静态代理
1.客户
package com.kuang.demo1;
//客户 租房子
public class client {
public static void main(String[] args) {
landlord land=new landlord();
proxy pro=new proxy(land);
pro.rent();
}
}
2.代理角色
package com.kuang.demo1;
//代理角色:中介 代理房东 出租房子 还可以做额外的事情
public class proxy implements rent{
private landlord land;
public proxy() {
}
public proxy(landlord land) {
this.land = land;
}
public void rent() {
land.rent();
seeHouse();
}
public void seeHouse(){
System.out.println("中介带你看房!");
}
}
3.真实角色
package com.kuang.demo1;
//真实角色:房东 出租房子
public class landlord implements rent{
public void rent() {
System.out.println("房东要出租房子!");
}
}
4.抽象角色
package com.kuang.demo1;
//抽象角色:租房事件
public interface rent {
public void rent();
}
5.静态代理的优缺点
优点:真实角色只关心自己的根本业务;公共业务代理实现;公共业务更容易扩展
缺点:一个真实角色就会产生一个代理角色 开发效率低
二、动态代理
1.客户
package com.kuang.demo2;
public class Client {
public static void main(String[] args) {
Landlord land=new Landlord();//创建真实角色
ProxyInvocationHandler pih=new ProxyInvocationHandler();
pih.setRent(land);//放入真实角色
Rent proxy=(Rent)pih.getProxy();//动态生成对应的代理类
proxy.rent();
proxy.buy();
}
}
2.代理角色(动态生成代理类)
package com.kuang.demo2;
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 setRent(Object target) {
this.target = target;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
//处理代理实例上的方法调用并返回结果
//proxy:代理类 method:代理类的调用处理程序的方法对象
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
//本质:利用反射实现
Object result =method.invoke(target,args);
return result;
}
public void log(String methodName){
System.out.println("执行了"+methodName+"方法");
}
}
3.真实角色
package com.kuang.demo2;
public class Landlord implements Rent{
public void rent() {
System.out.println("房东要出租房子!");
}
public void buy(){
System.out.println("房东又买了套新房子!");
}
}
4.抽象角色
package com.kuang.demo2;
public interface Rent {
void rent();
void buy();
}
5.代码执行结果
执行了rent方法
房东要出租房子!
执行了buy方法
房东又买了套新房子
6.动态代理的优点
一个动态代理 对应某一类业务(中介只负责租房等业务)
一个动态代理可以代理多个类 只要是实现了同一个接口即可(中介可以代理很多房东)
AOP
1.UserService接口
package com.kuang.service;
public interface UserService {
void add();
void delete();
void update();
void select();
}
2.UserServiceImpl接口实现类
package com.kuang.service;
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户!");
}
public void delete() {
System.out.println("删除了一个用户!");
}
public void update() {
System.out.println("更新了一个用户!");
}
public void select() {
System.out.println("查询了一个用户!");
}
}
一、使用原生Spring API接口实现AOP
3.Log类
package com.kuang.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了!");
}
}
4.AfterLog类
package com.kuang.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回结果为"+o);
}
}
5.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.kuang.service.UserServiceImpl"></bean>
<bean id="log" class="com.kuang.log.Log"></bean>
<bean id="afterLog" class="com.kuang.log.AfterLog"></bean>
<!--方式一:使用原生Spring API接口实现AOP-->
<!--配置AOP-->
<aop:config>
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"></aop:pointcut>
<!--执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="point"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="point"></aop:advisor>
</aop:config>
</beans>
二、使用自定义类实现AOP
3.自定义DiyPointCut类
package com.kuang.DIY;
//方式二:使用自定义类实现AOP
public class DiyPointCut {
public void before(){
System.out.println("---------方法执行前---------");
}
public void after(){
System.out.println("---------方法执行后---------");
}
}
4.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.kuang.service.UserServiceImpl"></bean>
<bean id="log" class="com.kuang.log.Log"></bean>
<bean id="afterLog" class="com.kuang.log.AfterLog"></bean>
<!--方式二:使用自定义类实现AOP-->
<bean id="diy" class="com.kuang.DIY.DiyPointCut"></bean>
<aop:config>
<!--自定义切面 ref 要引用的类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
</aop:aspect>
</aop:config>
</beans>
三、使用注解方式实现AOP
3.自定义的AnnotationPointCut类
package com.kuang.DIY;
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;
//方式三:使用注解方式实现AOP
@Aspect//标注这个类是一个切面
public class AnnotationPointCut {
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法执行前---------");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("签名:"+jp.getSignature());
//执行方法
Object proceed=jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
4.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.kuang.service.UserServiceImpl"></bean>
<bean id="log" class="com.kuang.log.Log"></bean>
<bean id="afterLog" class="com.kuang.log.AfterLog"></bean>
<!--方式三:使用注解方式实现AOP-->
<bean id="annotationPointCut" class="com.kuang.DIY.AnnotationPointCut"></bean>
<!--开启注解支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
四、测试类
import com.kuang.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=(UserService) context.getBean("userService");
userService.add();
}
}
Spring整合Mybatis
1.实体类User
package com.kuang.pojo;
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
2.接口UserMapper
package com.kuang.mapper;
import com.kuang.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectAll();
}
3.UserMapper.xml映射配置文件
<?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="com.kuang.mapper.UserMapper">
<select id="selectAll" resultType="user">
select * from mybatis.user
</select>
</mapper>
4.实现类UserMapperImpl
package com.kuang.mapper;
import com.kuang.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper{
// 方式一 需要接收传递的sqlSession
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> selectAll() {
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
return mapper.selectAll();
}
}
5.实现类UserMapperImpl2
package com.kuang.mapper;
import com.kuang.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
public List<User> selectAll() {
// 方式二 直接拿到sqlSession
SqlSession sqlSession=getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
return mapper.selectAll();
}
}
6.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="spring-mybatis.xml"></import>
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"></property>
</bean>
<bean id="userMapper2" class="com.kuang.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
</beans>
7.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置数据源DataSource:使用Spring的数据源 spring-jdbc-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"></property>
<property name="username" value="root"></property>
<property name="password" value="123qwe"></property>
</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>
<property name="mapperLocations" value="classpath*:com/kuang/mapper/*.xml"></property>
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能利用构造器注入参数 因为它没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
</beans>
8.mybatis-config.xml配置文件(主要配置别名和设置)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--别名-->
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
<!--设置-->
<!-- <settings>-->
<!-- <setting name="" value=""/>-->
<!-- </settings>-->
</configuration>
9.测试类
import com.kuang.mapper.UserMapper;
import com.kuang.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class MyTest {
@Test
public void test() {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper=context.getBean("userMapper2", UserMapper.class);
List<User> userList =userMapper.selectAll();
for (User user: userList){
System.out.println(user);
}
}
}
Spring中的事务管理
-
事务管理的分类
- 声明式事务
- 实际是AOP的应用,代码是横切进去的,不影响原有代码
- 编程式事务
- 需要在代码中进行事务的管理
- 项目中一般不用
- 声明式事务
-
举个栗子春暖花开(声明式事务)
1.实体类User
package com.kuang.pojo;
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
2.UserMapper.xml映射配置文件
package com.kuang.mapper;
import com.kuang.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectAll();
int addUser(User user);
int deleteUser(int id);
}
3.UserMapper.xml文件
<?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="com.kuang.mapper.UserMapper">
<select id="selectAll" 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>
4.接口实现类UserMapperImpl
package com.kuang.mapper;
import com.kuang.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{
public List<User> selectAll() {
User user=new User(8,"kk","9382820");
SqlSession sqlSession=getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
mapper.addUser(user);
mapper.deleteUser(8);
return mapper.selectAll();
}
public int addUser(User user) {
return getSqlSession().getMapper(UserMapper.class).addUser(user);
}
public int deleteUser(int id) {
return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
}
}
5.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="spring-mybatis.xml"></import>
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
</beans>
6.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--配置数据源DataSource:使用Spring的数据源 spring-jdbc-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"></property>
<property name="username" value="root"></property>
<property name="password" value="123qwe"></property>
</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>
<property name="mapperLocations" value="classpath*:com/kuang/mapper/*.xml"></property>
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能利用构造器注入参数 因为它没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
<!--配置声明式事务-->
<!--开启事务处理功能-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务 配置事务的传播特性(默认为REQUIRED)-->
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="select*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"></aop:advisor>
</aop:config>
</beans>
7.mybatis-config.xml配置文件(主要是设置和别名)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--别名-->
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
<!--设置-->
<!-- <settings>-->
<!-- <setting name="" value=""/>-->
<!-- </settings>-->
</configuration>
8.测试类
import com.kuang.mapper.UserMapper;
import com.kuang.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class MyTest {
@Test
public void test() {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper=context.getBean("userMapper", UserMapper.class);
List<User> userList =userMapper.selectAll();
for (User user: userList){
System.out.println(user);
}
}
}