spring笔记

2022/12/14 springjava

# 入门

1.导入Spring的核心jar包

spring-core-3.2.2.RELEASE.jar 核心工具类
spring-beans-3.2.2.RELEASE.jar 访问配置文件、创建和管理bean
spring-context-3.2.2.RELEASE.jar Spring提供在基础IoC功能上的扩展服务
spring-expression-3.2.2.RELEASE.jar Spring表达式语言
com.springsource.org.apache.commons.logging-1.1.1.jar 第三方的主要用于处理日志

2.编写service

package com.zh.service;

public interface IUserService {
    public void add();
}
package com.zh.service;

public class UserService implements IUserService{
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void add() {
        System.out.println("name:"+name);
    }
}

3.配置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对象,只能填写实现类,不能填接口-->
    <bean id="userService" class="com.zh.service.UserService">
        <!-- 注入依赖数据,调用set方法 -->
        <property name="name" value="张三"></property>
    </bean>

</beans>

4.测试

public class lesson01 {
    @Test
    public void test1(){
        //1.加载beans.xml
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //2.根据id获取bean
        IUserService userService = (UserService) context.getBean("userService");
        //3.调用add方法
        userService.add();
    }
}

控制台

name:张三

# 加载Spring容器的三种方式

1.类路径获得配置文件(最常用)

//通过类路径加载beans.xml
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

2.文件系统路径获得配置文件

//文件系统路径加载beans.xml
String path = "C:\\Users\\admin\\IdeaProjects\\spring\\src\\beans.xml";
ApplicationContext context = new FileSystemXmlApplicationContext(path);     

3.使用BeanFactory(了解)

//使用BeanFactory加载beans.xml
String path = "C:\\Users\\admin\\IdeaProjects\\spring\\src\\beans.xml";
BeanFactory context = new XmlBeanFactory(new FileSystemResource(path));

# 装配Bean(xml)

# 第一种方式:new实现类

<!-- 第一种方式: new 实现类-->
<bean name="userService" class="com.zh.service.UserService"></bean>

java

public class lesson01 {
    @Test
    public void test1(){
        //加载beans.xml
        ApplicationContext context = new ClassPathXmlApplicationContext("beans1.xml");
        //1.new对象
        IUserService userService = (UserService) context.getBean("userService");
        userService.add();
    }
}

控制台

name:null

# 第二种方式:使用静态工厂

//静态工厂类static
package com.zh.service;

public class UserSereviceFactory {
    public static IUserService createUserService(){
        return new UserService();
    }
}

xml

<!-- 第二种方式:通过静态工厂方法 spring的版本过低,3.0版本,把jdk改成1.7-->
<bean name="userService" class="com.zh.service.UserSereviceFactory" factory-method="createUserService"></bean>

java

public class lesson01 {
    @Test
    public void test1(){
        //加载beans.xml
        ApplicationContext context = new ClassPathXmlApplicationContext("beans1.xml");

        //使用工厂类创建对象
        IUserService userService = (UserService) context.getBean("userService");
        userService.add();
    }
}

控制台

name:null

# 第三种方式:使用实例工厂

//实例工厂类
package com.zh.service;
public class UserSereviceFactory2 {
    public IUserService createUserService(){
        return new UserService();
    }
}

xml

<!--第三种方式:通过实例工厂方法 -->
<!-- 1.创建实例工厂bean -->
<bean name="factory2" class="com.zh.service.UserSereviceFactory2"></bean>
 <!-- 2.使用工厂bean -->
<bean name="userService" factory-bean="factory2" factory-method="createUserService"></bean>

java

public class lesson01 {
    @Test
    public void test1(){
        //加载beans.xml
        ApplicationContext context = new ClassPathXmlApplicationContext("beans1.xml");

        //使用实例工厂类创建对象
        IUserService userService = (UserService) context.getBean("userService");
        userService.add();
    }
}

控制台

name:null

# bean的作用域

掌握前两个常用的即可

类别 说明
singleton 在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在,默认值
prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean()

# 第一种:单例

<!-- 单例方式-->
<bean id="userService" class="com.zh.service.UserService" scope="singleton"></bean>

java

public class lesson02 {
    @Test
    public void test1(){
        //1.加载beans.xml
        ApplicationContext context = new ClassPathXmlApplicationContext("beans2.xml");

        //2.从容器获取两个bean
        IUserService userService1 = (IUserService) context.getBean("userService");
        IUserService userService2 = (IUserService) context.getBean("userService");

        //3.查看是否是同一个对象
        System.out.println(userService1);
        System.out.println(userService2);
    }
}

控制台

com.zh.service.UserService@184f6be2
com.zh.service.UserService@184f6be2

# 第二种:多例

<!-- 多例方式-->
<bean id="userService" class="com.zh.service.UserService" scope="prototype"></bean>

控制台

com.zh.service.UserService@527740a2
com.zh.service.UserService@13a5fe33

# 数据的注入

# 1.构造方法注入

package com.zh.model;

public class User {
    private String username;
    private String password;
    private Integer age;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public User(String username, Integer age) {
        this.username = username;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}
<!--1.构造方法注入=属性值-->
<bean id="user" class="com.zh.model.User">
    <constructor-arg name="username" value="张三"></constructor-arg>
    <constructor-arg name="password" value="123"></constructor-arg>
</bean>

java

public class lesson03 {
    @Test
    public void test1(){
        //加载beans.xml
        ApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
        //1.构造方法注入
        User user = (User) context.getBean("user");
        System.out.println(user);
    }
}

控制台

User{username='张三', password='123', age=null}

# 2通过索引加类型给构造方法赋值

<!-- 2.通过索引加类型 给构造方法赋值-->
<bean id="user" class="com.zh.model.User">
    <constructor-arg index="0" value="张三" type="java.lang.String"></constructor-arg>
    <constructor-arg index="1" value="123" type="java.lang.Integer"></constructor-arg>
</bean>

控制台

User{username='张三', password='123', age=null}

# 3.通过set方法往bean注入属性值

//需要提供无参构造方法
package com.zh.model;

public class User {
    private String username;
    private String password;
    private Integer age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }
}
<!-- 3.通过set方法往bean注入属性值-->
<bean id="user" class="com.zh.model.User">
    <property name="username" value="张三"></property>
    <property name="password" value="123"></property>
    <property name="age" value="20"></property>
</bean>

控制台

User{username='张三', password='123', age=20}

# 4.通过p命名空间注入

<!-- 命名空间 -->
xmlns:p ="http://www.springframework.org/schema/p"
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p ="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--3.通过p命名空间注入-->
    <bean id="user" class="com.zh.model.User" p:username="张三" p:password="123" p:age="20"></bean>
</beans>

控制台

User{username='张三', password='123', age=20}

# SpEL表达式

# 数字、字符串

<bean id="user" class="com.zh.model.User">
    <!--字符串-->
    <property name="username" value="#{'张三'}"></property>
    <!--数字-->
    <property name="age" value="#{5}"></property>
</bean>

控制台

User{username='张三', password='null', age=5}

# 引用另一个对象

  • ref: 引用ref="要引用bean的id"
  • SpEL:value="#{要引用bean的id}"
package com.zh.model;

public class Customer {
    private String name;
    private String sex = "男";//性别
    private double pi;//性别

    private Address address;
}
package com.zh.model;

public class Address {
    private String name;
}
<!--
    一个对象引用另外一个对象两写法
    1.ref: 引用<property name="address" ref="address"></property>
    2.SpEL:<property name="address" value="#{address}"></property>
-->
<bean id="address" class="com.zh.model.Address">
    <property name="name" value="武汉"></property>
</bean>

<!-- 一个对象引用另外一个对象两写法-->
<bean id="customer" class="com.zh.model.Customer">
    <property name="address" value="#{address}"></property>
</bean>

java

public class lesson04 {
    @Test
    public void test1(){
        //加载beans.xml
        ApplicationContext context = new ClassPathXmlApplicationContext("beans4.xml");
        //1.构造方法注入
        Customer customer = (Customer) context.getBean("customer");
        System.out.println(customer);
    }
}

控制台

Customer{name='null', sex='男', pi=0.0, address=Address{name='武汉'}}

# 执行方法

<!-- 执行方法 -->
<bean id="customer" class="com.zh.model.Customer">
    <property name="name" value="#{'abc'.toUpperCase()}"></property>
</bean>

控制台

Customer{name='ABC', sex='男', pi=0.0, address=null}

# 静态方法

<!-- Math.PI 调用静态方法 -->
<bean id="customer" class="com.zh.model.Customer">
    <property name="pi" value="#{T(java.lang.Math).PI}"></property>
</bean>

控制台

Customer{name='null', sex='男', pi=3.141592653589793, address=null}

# 集合注入

# 1.List注入

public class Programmer {
    private List<String> cars;

    public List<String> getCars() {
        return cars;
    }

    public void setCars(List<String> cars) {
        this.cars = cars;
    }
}

xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p ="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<!-- list注入 -->
    <bean name="programe" class="com.zh.model.Programmer">
        <property name="cars">
            <list>
                <value>ofo</value>
                <value>mobike</value>
            </list>
        </property>
    </bean>
</beans>

java

public class lesson04 {
    @Test
    public void test1(){
        //加载beans.xml
        ApplicationContext context = new ClassPathXmlApplicationContext("beans5.xml");
        Programmer programmer = (Programmer) context.getBean("programe");
        System.out.println(programmer.getCars());
    }
}

控制台

[ofo, mobike]

# 2.Set注入

package com.zh.model;

import java.util.List;
import java.util.Set;

public class Programmer {
    private Set<String> pats;

    public Set<String> getPats() {
        return pats;
    }

    public void setPats(Set<String> pats) {
        this.pats = pats;
    }
}
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p ="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- set数据注入-->
    <bean name="programe" class="com.zh.model.Programmer">
        <property name="pats">
            <set>
                <value>机器猫</value>
                <value>加菲猫</value>
            </set>
        </property>
    </bean>
</beans>

控制台

[机器猫, 加菲猫]

# 3.Map注入

public class Programmer {
    private Map<String,String> info;

    public Map<String, String> getInfo() {
        return info;
    }

    public void setInfo(Map<String, String> info) {
        this.info = info;
    }
}

xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p ="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- map数据注入-->
    <bean name="programe" class="com.zh.model.Programmer">
        <property name="info">
            <map>
                <entry key="name" value="zhang"></entry>
                <entry key="age" value="20"></entry>
            </map>
        </property>
    </bean>
</beans>

控制台

{name=zhang, age=20}

# 4.Properties注入

public class Programmer {
   private Properties mysqlinfo;

    public Properties getMysqlinfo() {
        return mysqlinfo;
    }

    public void setMysqlinfo(Properties mysqlinfo) {
        this.mysqlinfo = mysqlinfo;
    }
}
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p ="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- Properties数据注入-->
    <bean name="programe" class="com.zh.model.Programmer">
        <property name="mysqlinfo">
            <props>
                <prop key="url">mysql:jdbc://localhost:3306/dbname</prop>
                <prop key="user">root</prop>
                <prop key="password">www</prop>
            </props>
        </property>
    </bean>
</beans>

控制台

{user=root, url=mysql:jdbc://localhost:3306/dbname, password=www}

# 5.数组注入

public class Programmer {
   private String[] member;

    public String[] getMember() {
        return member;
    }

    public void setMember(String[] member) {
        this.member = member;
    }
}
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p ="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 数组数据注入-->
    <bean name="programe" class="com.zh.model.Programmer">
        <property name="member">
            <array>
                <value>father</value>
                <value>mother</value>
                <value>brother</value>
            </array>
        </property>
    </bean>
</beans>

java

public class lesson04 {
    @Test
    public void test1(){
        //加载beans.xml
        ApplicationContext context = new ClassPathXmlApplicationContext("beans5.xml");
        Programmer programmer = (Programmer) context.getBean("programe");
        System.out.println(programmer.getMember()[1]);
    }
}

控制台

mother

# 注解注入

开发中:使用注解取代 xml配置文件

@component`取代`<bean class="">
@Component("id")` 取代 `<bean id="" class="">

web开发,提供3个@Component注解衍生注解(功能一样)取代<bean class="">

@Repository(“名称”):dao层

@Service(“名称”):service层

@Controller(“名称”):web层

@Autowired:自动根据类型注入

@Qualifier(“名称”):指定自动注入的id名称

@Resource(“名称”)

@ PostConstruct 自定义初始化

@ PreDestroy 自定义销毁

# 第一个案例

<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
                        http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 开启注解-->
    <context:annotation-config />
    <!-- 注解的位置-->
    <context:component-scan base-package="com.zh"/>
</beans>

Dao层

//User
package com.zh.model;

public class User {
    private String username;
    private String password;
    private Integer age;
}

service

//实现类
@Component
public class UserServiceImpl implements IUserService{
    @Override
    public void add(User user) {
        System.out.println("service 添加用户:" + user);
    }
}

java

//没配置id,通过类型获取
public class lesson05 {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans6.xml");
        //1.如果@Component没配置id,通过类型获取
        IUserService userService = context.getBean(UserServiceImpl.class);

        User user = new User();
        user.setUsername("章三");
        user.setPassword("123");
        user.setAge(10);

        userService.add(user);

    }
}

控制台

service 添加用户:User{username='章三', password='123', age=10}

# 第二个案例

//实现类
@Component("userService")
public class UserServiceImpl implements IUserService{
    @Override
    public void add(User user) {
        System.out.println("service 添加用户:" + user);
    }
}

java

//2.如果@Component("userService),配置了id,就可以通过id来获取
IUserService userService = (IUserService) context.getBean("userService");

控制台

service 添加用户:User{username='章三', password='123', age=10}

# 第三个案例

Dao层

package com.zh.dao;

import com.zh.model.User;

public class UserDaoImpl implements IUserDao{

    @Override
    public void add(User user) {
        System.out.println("dao 添加用户:"+user);
    }
}

service层

package com.zh.service;

import com.zh.dao.IUserDao;
import com.zh.model.User;

public class UserServiceImpl implements IUserService{
    private IUserDao userDao;

    @Override
    public void add(User user) {
        System.out.println("service 添加用户:" + user);
        //调用Dao
        userDao.add(user);
    }

    public IUserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(IUserDao userDao) {
        this.userDao = userDao;
    }
}

web层

//web层
package com.zh.web.action;

import com.zh.model.User;
import com.zh.service.IUserService;

public class UserAction {
    private IUserService userService;
    public void save(User user){
        System.out.println("action save方法");
        userService.add(user);
    }

    public IUserService getUserService() {
        return userService;
    }

    public void setUserService(IUserService userService) {
        this.userService = userService;
    }
}
<!-- 配置dao -->
<bean name="userDao" class="com.zh.dao.UserDaoImpl"></bean>

<!-- 配置service -->
<bean name="userService" class="com.zh.service.UserServiceImpl">
    <property name="userDao" ref="userDao"></property>
</bean>

<!-- 配置action -->
<bean id="userAction" class="com.zh.web.action.UserAction">
   <property name="userService" ref="userService"></property>
</bean>

java

public class lesson05 {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans7.xml");

        //1.获取service对象
        UserAction userAction = (UserAction) context.getBean("userAction");

        //2.创建user对象
        User user = new User();
        user.setUsername("张三");
        user.setPassword("mima");
        user.setAge(22);

        //3.调用方法
        userAction.save(user);
    }
}

控制台

action save方法
service 添加用户:User{username='张三', password='mima', age=22}
dao 添加用户:User{username='张三', password='mima', age=22}

2.使用注解

//dao层
@Repository
public class UserDaoImpl implements IUserDao{

    @Override
    public void add(User user) {
        System.out.println("dao 添加用户:"+user);
    }
}
//serve层
@Service
public class UserServiceImpl implements IUserService{
    @Autowired
    private IUserDao userDao;//spring会自动往userDao赋值

    @Override
    public void add(User user) {
        System.out.println("service 添加用户:" + user);
        //调用Dao
        userDao.add(user);
    }

}

java

//web层
@Controller
public class UserAction {
    @Autowired
    private IUserService userService;
    public void save(User user){
        System.out.println("action save方法");
        userService.add(user);
    }

}

java

public class lesson06 {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans6.xml");

        //1.获取action对象
        UserAction userAction = context.getBean(UserAction.class);

        //2.创建user对象
        User user = new User();
        user.setUsername("张三");
        user.setPassword("mima");
        user.setAge(22);

        userAction.save(user);

    }
}

控制台

action save方法
service 添加用户:User{username='张三', password='mima', age=22}
dao 添加用户:User{username='张三', password='mima', age=22}

# 第四个案例

指定注入的id

//指定id
@Service("myUserService")
public class UserServiceImpl implements IUserService{
    @Autowired
    private IUserDao userDao;//spring会自动往userDao赋值

    @Override
    public void add(User user) {
        System.out.println("service 添加用户:" + user);
        //调用Dao
        userDao.add(user);
    }

}


java

//web层
@Controller
public class UserAction {
    @Autowired
    @Qualifier("myUserService")//指定注入的id
    private IUserService userService;
    public void save(User user){
        System.out.println("action save方法");
        userService.add(user);
    }

}
//上面可替换
//@Autowired
//@Qualifier("myUserService")//指定注入的id
@Resource(name="myUserService")

# 第五个案例

1.默认单例

@Controller
public class UserAction {
    @Autowired
    private IUserService userService;
    public void save(User user){
        System.out.println("action save方法");
        userService.add(user);
    }

}

java

public class lesson07 {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans6.xml");

        //1.获取action对象
        UserAction userAction1 = context.getBean(UserAction.class);
        UserAction userAction2 = context.getBean(UserAction.class);

        System.out.println(userAction1);
        System.out.println(userAction2);
    }
}

控制台

com.zh.web.action.UserAction@3fc15856
com.zh.web.action.UserAction@3fc15856

2.多例配置

@Controller
@Scope("prototype") //多例配置
public class UserAction {
    @Autowired
    private IUserService userService;
    public void save(User user){
        System.out.println("action save方法");
        userService.add(user);
    }

}

控制台

com.zh.web.action.UserAction@78c1d004
com.zh.web.action.UserAction@7c3ff48b

# 第六个案例

//dao层
@Repository
public class UserDaoImpl implements IUserDao{
    // <bean init-method="" destroy-method=""></bean>
    @PostConstruct
    public void myInit(){
        System.out.println("自定义初始化方法。。。");
    }

    @PreDestroy
    public void myDestroy(){
        System.out.println("自定义销毁方法。。。");
    }
    @Override
    public void add(User user) {
        System.out.println("dao 添加用户:"+user);
    }
}

java

//action
public class lesson07 {
    @Test
    public void test1() throws Exception{
        ApplicationContext context = new ClassPathXmlApplicationContext("beans6.xml");

        //1.获取action对象
        UserAction userAction1 = context.getBean(UserAction.class);
		
        //2.关闭context
        context.getClass().getMethod("close").invoke(context);
    }
}

控制台

自定义初始化方法。。。
自定义销毁方法。。。

# AOP动态代理

# JDK动态代理

1.目标类

import com.zh.model.User;

public interface IUserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}
@Service
public class UserServiceImpl implements IUserService{

    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void updateUser() {
        System.out.println("更新用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

2.切面类

package com.zh.service;

public class MyAspec {
    public void before(){
        System.out.println("开启事务");
    }

    public void after(){
        System.out.println("提交事务");
    }
}

3.工厂类

public class MyBeanFactory {

    public static IUserService createUserService(){
        //1.创建目标对象target
        final IUserService userService = new UserServiceImpl();
        //2.声明切面类对象
        final MyAspec aspec = new MyAspec();
        //3.把切面类2个方法 应用到目标类

        //3.1创建JDK代理
        /*
            参数1 类加载器,写当前类
            参数2 接口:接口下的方法会被拦截
            参数3 处理
         */
       IUserService serviceProxy = (IUserService) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
                userService.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //开启事务
                        aspec.before();
                        //放行代码,业务方法返回值
                        Object retObj = method.invoke(userService,args);
                        //System.out.println("拦截换回值"+retObj);

                        //提交事务
                        aspec.after();
                        return retObj;
                    }
                }
        );
        return serviceProxy;
    }
}

4.测试类

public class lesson08 {
    @Test
    public void test1(){
        //自用实现AOP编程,使用JDK代理来实现
        IUserService userService = MyBeanFactory.createUserService();
        userService.addUser();
    }
}

控制台

开启事务
添加用户
提交事务

# cglib增强字节码代理

⭐ 没有接口,只有实现类。

⭐ 采用字节码增强框架 cglib,在运行时 创建目标类的子类,从而对目标类进行增强。

⭐ 导入jar包:

自己导包(了解):

核心:hibernate-distribution-3.6.10.Final\lib\bytecode\cglib\cglib-2.2.jar

依赖:struts-2.3.15.3\apps\struts2-blank\WEB-INF\lib\asm-3.3.jar

采用字节码增强框架 cglib,在运行时 创建目标类的子类(继承),从而对目标类进行增强。

//目标类接口
public interface IUserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
    public int deleteUser(int id);
}
//目标类实现
public class UserServiceImpl implements IUserService{

    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void updateUser() {
        System.out.println("更新用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }

    @Override
    public int deleteUser(int id) {
        System.out.println("通过id删除用户");
        return 1;
    }
}
//切面类
public class MyAspec {
    public void before(){
        System.out.println("开启事务...");
    }

    public void after(){
        System.out.println("提交事务...");
    }
}
//代理类
public class MyBeanFactory {
    // cglib实现代理
    public static IUserService createUserService(){
        //1.目标类
        final IUserService userService = new UserServiceImpl();

        //2.切面类
        final MyAspec aspec = new MyAspec();

        //3.cglib核心类
        Enhancer enhancer = new Enhancer();
        //4.设置父类
        enhancer.setSuperclass(userService.getClass());
        //5.设置回调【拦截】
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //执行代理类的方法
                aspec.before();
                Object obj = method.invoke(userService,args);
                //Object obj = methodProxy.invokeSuper(proxy,objects);
                aspec.after();
                return obj;
            }
        });

        //创建代理对象
        UserServiceImpl proxy = (UserServiceImpl) enhancer.create();
        return proxy;
    }
}

java

//测试类
public class lesson09 {
    @Test
    public void test1(){
        //采用cglib实现动态代理
        IUserService userService = MyBeanFactory.createUserService();
        userService.addUser();
    }
}

控制台

开启事务...
添加用户
提交事务...

# 半自动代理

【核心4+1 、AOP联盟(规范)、spring-aop (实现)】

1.目标类

//目标类接口
package com.zh.service;

public interface IUserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}

java

//目标类实现
public class UserServiceImpl implements IUserService{

    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void updateUser() {
        System.out.println("更新用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

2.切面类

package com.zh.service;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//MethodInterceptor导入的是aop联盟下的包
public class MyAspect implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        //拦截方法
        //开启事务
        System.out.println("开启事务...");
        //放行
        Object obj = methodInvocation.proceed();
        //提交事务
        System.out.println("提交事务...");
        return obj;
    }
}

3.spring配置

<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 name="userService" class="com.zh.service.UserServiceImpl"></bean>
    <!-- 配置切面类  -->
    <bean id="myAspect" class="com.zh.service.MyAspect"></bean>

    <!-- 配置代理  -->
    <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 接口:如果只是一个接口,就写Value,如果是多个接口就写List-->
        <property name="interfaces" value="com.zh.service.IUserService"></property>

        <!-- 目标类 -->
        <property name="target" ref="userService"></property>

        <!-- 切面类 -->
        <property name="interceptorNames" value="myAspect"></property>

        <!-- 不配置默认就是JDK的Proxy实现,配置使用cglib生成 -->
        <property name="optimize" value="true"></property>

    </bean>
</beans>

4.测试

public class lesson09 {
    @Test
    public void test1(){
        //spring半自动代理
        ApplicationContext context = new ClassPathXmlApplicationContext("beans9.xml");

        //创建代理对象
        IUserService userService = (IUserService) context.getBean("serviceProxy");
        userService.addUser();
    }
}

控制台

开启事务...
添加用户
提交事务...

# AOP全自动代理

spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE

1.目标类

//目标类接口
package com.zh.service;

public interface IUserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}
//目标类实现
public class UserServiceImpl implements IUserService{

    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void updateUser() {
        System.out.println("更新用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

2.切面类

package com.zh.service;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//MethodInterceptor导入的是aop联盟下的包
public class MyAspect implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        //拦截方法
        //开启事务
        System.out.println("开启事务...");
        //放行
        Object obj = methodInvocation.proceed();
        //提交事务
        System.out.println("提交事务...");
        return obj;
    }
}

3.spring配置

<!-- 引入提示 -->
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
<?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 name="userService" class="com.zh.service.UserServiceImpl"></bean>
    <!-- 配置切面类  -->
    <bean id="myAspect" class="com.zh.service.MyAspect"></bean>

    <!-- 配置代理  -->
    <!-- proxy-target-class:使用cglib实现代理 -->
    <aop:config proxy-target-class="true">
        <!-- 切入点: proxy-target-class:使用cglib实现代理
        expression 表达式:*任意
        execution(*          com.gyf.service.*.       *          (..))
                  任意返回值     包名        任意类名  任意方法名  任意参数-->
        <aop:pointcut id="mycut" expression="execution(* com.zh.service.*.*(..))"/>
        <!-- advice-ref切面类,pointcut-ref 切入点引用-->
        <aop:advisor advice-ref="myAspect" pointcut-ref="mycut"></aop:advisor>
    </aop:config>
</beans>

4.测试

public class lesson10 {
    @Test
    public void test1(){
        //spring全自动代理
        ApplicationContext context = new ClassPathXmlApplicationContext("beans10.xml");

        //直接创建userService
        IUserService userService = (IUserService) context.getBean("userService");
        userService.addUser();
    }
}

控制台

开启事务...
添加用户
提交事务...

# AspectJ

AspectJ是一个基于Java语言的AOP框架

Spring2.0以后新增了对AspectJ切点表达式支持

@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面

新版本 Spring 框架,建议使用 AspectJ 方式来开发 AOP

主要用途:自定义开发

# 前后置通知

1.目标类

//目标类接口
package com.zh.service;

public interface IUserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}
//目标类实现
public class UserServiceImpl implements IUserService{

    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void updateUser() {
        System.out.println("更新用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

2.切面类

package com.zh.aspect;

public class MyAspect{
    //自定义的前置通知
    public void myBefore(){
        System.out.println("前置通知...");
    }

    //自定义的后置通知
    public void myAfterReturning(){
        System.out.println("后置通知...");
    }
}

3.配置文件

<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 name="userService" class="com.zh.service.UserServiceImpl"></bean>
    <!-- 配置切面类  -->
    <bean id="myAspect" class="com.zh.aspect.MyAspect"></bean>

    <!-- 配置aop -->
    <aop:config>
        <!-- aop:指定切面类-->
        <aop:aspect ref="myAspect">
            <!-- 定义一个切入点 -->
            <aop:pointcut id="mypointcut" expression="execution(* com.zh.service.*.*(..))"/>

            <!-- 前置通知 method:切面类中的方法名-->
            <aop:before method="myBefore" pointcut-ref="mypointcut"></aop:before>
            <!-- 后置通知 -->
            <aop:after-returning method="myAfterReturning" pointcut-ref="mypointcut"></aop:after-returning>
        </aop:aspect>
    </aop:config>
</beans>

4.测试

public class lesson11 {
    @Test
    public void test1(){
        //AspectJ全自动代理
        ApplicationContext context = new ClassPathXmlApplicationContext("beans10.xml");

        //直接创建userService
        IUserService userService = (IUserService) context.getBean("userService");
        userService.addUser();
    }
}

控制台

//前后置通知可以单独使用
前置通知...
添加用户
后置通知...

# 环绕通知

1.目标类

//目标类接口
package com.zh.service;

public interface IUserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}
//目标类实现
public class UserServiceImpl implements IUserService{

    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void updateUser() {
        System.out.println("更新用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

2.切面类

package com.zh.aspect;

import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect{

    //自定义环绕通知
    public void myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("开启事务...");
        Object reobj = pjp.proceed();
        System.out.println("提交事务...");
    }
}

3.配置文件

<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 name="userService" class="com.zh.service.UserServiceImpl"></bean>
    <!-- 配置切面类  -->
    <bean id="myAspect" class="com.zh.aspect.MyAspect"></bean>

    <!-- 配置aop -->
    <aop:config>
        <!-- aop:指定切面-->
        <aop:aspect ref="myAspect">
            <!-- 定义一个切入点 -->
            <aop:pointcut id="mypointcut" expression="execution(* com.zh.service.*.*(..))"/>
            <!-- 环绕通知 -->
            <aop:around method="myAround" pointcut-ref="mypointcut"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>

4.测试

public class lesson11 {
    @Test
    public void test1(){
        //AspectJ全自动代理
        ApplicationContext context = new ClassPathXmlApplicationContext("beans10.xml");

        //直接创建userService
        IUserService userService = (IUserService) context.getBean("userService");
        userService.addUser();
    }
}

控制台

开启事务...
添加用户
提交事务...

# 通知的执行顺序

/*
JoinPoint可以获取代理对象方法名
ProceedingJoinPoint 可以获取代理对象方法名+放行
*/
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect{
    //自定义的前置通知
    public void myBefore(JoinPoint jp){
        System.out.println("前置通知--"+jp.getSignature().getName());
    }

    //自定义的后置通知
    public void myAfterReturning(JoinPoint jp){
        System.out.println("后置通知--"+jp.getSignature().getName());
    }

    //自定义环绕通知
    public void myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕通知--开启事务..."+pjp.getSignature().getName());
        Object reobj = pjp.proceed();
        System.out.println("环绕通知--提交事务..."+pjp.getSignature().getName());
    }
}

控制台

前置通知--addUser
环绕通知--开启事务...addUser
添加用户
后置通知--addUser
环绕通知--提交事务...addUser

# 异常通知

public class UserServiceImpl implements IUserService{
    public void deleteUser() {
        System.out.println("删除用户");
        //制造一个异常
        int i = 10/0;
    }
}

java

//自定义异常通知
public void myAfterThrowing(JoinPoint jp,Throwable e){
	System.out.println("异常通知:" + jp.getSignature().getName() + "===" +e.getMessage());
}

xml

<!-- 异常通知 throwing 异常方法名-->
<aop:after-throwing method="myAfterThrowing" pointcut-ref="mypointcut" throwing="e"></aop:after-throwing>

java

public class lesson11 {
    @Test
    public void test1(){
        //AspectJ全自动代理
        ApplicationContext context = new ClassPathXmlApplicationContext("beans10.xml");

        //直接创建userService
        IUserService userService = (IUserService) context.getBean("userService");
        userService.deleteUser();
    }
}

控制台

异常通知:deleteUser===/ by zero

java.lang.ArithmeticException: / by zero

1.目标类

//目标类接口
package com.zh.service;

public interface IUserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}

java

//目标类实现
public class UserServiceImpl implements IUserService{

    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void updateUser() {
        System.out.println("更新用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
         //制造一个异常
        int i = 10/0;
    }
}

2.切面类

public class MyAspect{
    //自定义的前置通知
    public void myBefore(JoinPoint jp){
        System.out.println("前置通知--"+jp.getSignature().getName());
    }

    //自定义的后置通知
    public void myAfterReturning(JoinPoint jp){
        System.out.println("后置通知--"+jp.getSignature().getName());
    }

    //自定义环绕通知
    public void myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕通知--开启事务..."+pjp.getSignature().getName());
        Object reobj = pjp.proceed();
        System.out.println("环绕通知--提交事务..."+pjp.getSignature().getName());
    }

    //自定义异常通知
    public void myAfterThrowing(JoinPoint jp,Throwable e){
        System.out.println("异常通知:" + jp.getSignature().getName() + "===" + e.getMessage());
    }
}

3.配置文件

<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 name="userService" class="com.zh.service.UserServiceImpl"></bean>
    <!-- 配置切面类  -->
    <bean id="myAspect" class="com.zh.aspect.MyAspect"></bean>

    <!-- 配置aop -->
    <aop:config>
        <!-- aop:指定切面-->
        <aop:aspect ref="myAspect">
            <!-- 定义一个切入点 -->
            <aop:pointcut id="mypointcut" expression="execution(* com.zh.service.*.*(..))"/>

            <!-- 前置通知 -->
            <aop:before method="myBefore" pointcut-ref="mypointcut"></aop:before>
            <!-- 后置通知 -->
            <aop:after-returning method="myAfterReturning" pointcut-ref="mypointcut"></aop:after-returning>

            <!-- 环绕通知 -->
            <aop:around method="myAround" pointcut-ref="mypointcut"></aop:around>

            <!-- 异常通知 throwing 异常方法名-->
            <aop:after-throwing method="myAfterThrowing" pointcut-ref="mypointcut" throwing="e"></aop:after-throwing>
        </aop:aspect>
    </aop:config>
</beans>

4.测试类

public class lesson11 {
    @Test
    public void test1(){
        //AspectJ全自动代理
        ApplicationContext context = new ClassPathXmlApplicationContext("beans10.xml");

        //直接创建userService
        IUserService userService = (IUserService) context.getBean("userService");
        userService.deleteUser();
    }
}

控制台

前置通知--deleteUser
环绕通知--开启事务...deleteUser
删除用户
后置通知--deleteUser
异常通知:deleteUser===/ by zero

java.lang.ArithmeticException: / by zero

# 最终通知

//自定义最终通知--不管是否异常都会执行
public void myAfter(){
    System.out.println("最终通知--");
}

xml

<!-- 最终通知 -->
<aop:after method="myAfter" pointcut-ref="mypointcut"></aop:after>

控制台

删除用户
最终通知--

1.目标类

//目标类接口
package com.zh.service;

public interface IUserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}

java

//目标类实现
public class UserServiceImpl implements IUserService{

    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void updateUser() {
        System.out.println("更新用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
         //制造一个异常
        int i = 10/0;
    }
}

2.切面类

public class MyAspect{
    //自定义的前置通知
    public void myBefore(JoinPoint jp){
        System.out.println("前置通知--"+jp.getSignature().getName());
    }

    //自定义的后置通知
    public void myAfterReturning(JoinPoint jp){
        System.out.println("后置通知--"+jp.getSignature().getName());
    }

    //自定义环绕通知
    public void myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕通知--开启事务..."+pjp.getSignature().getName());
        Object reobj = pjp.proceed();
        System.out.println("环绕通知--提交事务..."+pjp.getSignature().getName());
    }

    //自定义异常通知
    public void myAfterThrowing(JoinPoint jp,Throwable e){
        System.out.println("异常通知:" + jp.getSignature().getName() + "===" + e.getMessage());
        
    }
    //自定义最终通知
    public void myAfter(){
        System.out.println("最终通知--");
    }
}

3.配置文件

<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 name="userService" class="com.zh.service.UserServiceImpl"></bean>
    <!-- 配置切面类  -->
    <bean id="myAspect" class="com.zh.aspect.MyAspect"></bean>

    <!-- 配置aop -->
    <aop:config>
        <!-- aop:指定切面-->
        <aop:aspect ref="myAspect">
            <!-- 定义一个切入点 -->
            <aop:pointcut id="mypointcut" expression="execution(* com.zh.service.*.*(..))"/>

            <!-- 前置通知 -->
            <aop:before method="myBefore" pointcut-ref="mypointcut"></aop:before>
            <!-- 后置通知 -->
            <aop:after-returning method="myAfterReturning" pointcut-ref="mypointcut"></aop:after-returning>

            <!-- 环绕通知 -->
            <aop:around method="myAround" pointcut-ref="mypointcut"></aop:around>

            <!-- 异常通知 throwing 异常方法名-->
            <aop:after-throwing method="myAfterThrowing" pointcut-ref="mypointcut" throwing="e"></aop:after-throwing>
            
            <!-- 最终通知 -->
            <aop:after method="myAfter" pointcut-ref="mypointcut"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

4.测试类

public class lesson11 {
    @Test
    public void test1(){
        //AspectJ全自动代理
        ApplicationContext context = new ClassPathXmlApplicationContext("beans10.xml");

        //直接创建userService
        IUserService userService = (IUserService) context.getBean("userService");
        userService.deleteUser();
    }
}

控制台

前置通知--deleteUser
环绕通知--开启事务...deleteUser
删除用户
异常通知:deleteUser===/ by zero
最终通知--

java.lang.ArithmeticException: / by zero

# 后置通知返回值

public String deleteUser(String id) {
   System.out.println("通过id删除用户");
   return id;
}

java

//自定义的后置通知
public void myAfterReturning(JoinPoint jp, Object retValue){
    System.out.println("后置通知--"+jp.getSignature().getName());
    System.out.println("返回值:" + retValue);
}

xml

<!-- 后置通知 returning:返回值对象名-->
<aop:after-returning method="myAfterReturning" pointcut-ref="mypointcut" returning="retValue"></aop:after-returning>

java

public class lesson11 {
    @Test
    public void test1(){
        //AspectJ全自动代理
        ApplicationContext context = new ClassPathXmlApplicationContext("beans10.xml");

        //直接创建userService
        IUserService userService = (IUserService) context.getBean("userService");
        userService.deleteUser("2");
    }
}

控制台

通过id删除用户
返回值:2

# 使用注解配置

第1步:声明使用注解

<!-- 扫描注解 -->
<context:component-scan base-package="com.zh"></context:component-scan>
<!-- 确定AOP注解生效 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

第2步:用注解替换service和 切面 bean

&lt;!-- 配置目标类 -->
&lt;bean name="userService" class="com.zh.service.UserServiceImpl">&lt;/bean>
&lt;!-- 配置切面类  -->
&lt;bean id="myAspect" class="com.zh.aspect.MyAspect">&lt;/bean>

用注解代替

//<bean name="userService" class="com.zh.service.UserServiceImpl"></bean>
@Service("userService")
public class UserServiceImpl implements IUserService{
    @Override
    public void addUser() {
        System.out.println("添加用户");
    }
}

java

//<bean id="myAspect" class="com.zh.aspect.MyAspect"></bean>
@Component
public class MyAspect{
    .....
}

第3步:声明切面

<!-- aop:指定切面-->
<aop:aspect ref="myAspect"></aop:aspect>

java

@Component
//<aop:aspect ref="myAspect"></aop:aspect>
@Aspect
public class MyAspect{
	......
}

第4步:声明前置通知

<!-- 定义一个切入点 -->
<aop:pointcut id="mypointcut" expression="execution(* com.zh.service.*.*(..))"/>
<!-- 前置通知 -->
<aop:before method="myBefore" pointcut-ref="mypointcut"></aop:before>

java

@Before("execution(* com.zh.service.*.*(..))")
public void myBefore(JoinPoint jp){
	System.out.println("前置通知--"+jp.getSignature().getName());
}

第5步:声明公共切入点

<!-- 定义一个切入点 -->
<aop:pointcut id="mypointcut" expression="execution(* com.zh.service.*.*(..))"/>

java

 //声明公共切入点
@Pointcut("execution(* com.zh.service.*.*(..))")
public void myPoinCut(){
}

java

//自定义的前置通知
//@Before("execution(* com.zh.service.*.*(..))")
@Before(value = "myPoinCut()")
public void myBefore(JoinPoint jp){
   System.out.println("前置通知--"+jp.getSignature().getName());
}

第6步:声明后置通知

<!-- 后置通知 -->
<aop:after-returning method="myAfterReturning" pointcut-ref="mypointcut" returning="retValue"></aop:after-returning>

java

//自定义的后置通知
@AfterReturning(value = "myPoinCut()",returning = "retValue")
public void myAfterReturning(JoinPoint jp, Object retValue){
	System.out.println("后置通知--"+jp.getSignature().getName());
	System.out.println("返回值:" + retValue);
}

第7步:声明环绕通知

<!-- 环绕通知 -->
<aop:around method="myAround" pointcut-ref="mypointcut"></aop:around>

java

//自定义环绕通知
@Around(value = "myPoinCut()")
public void myAround(ProceedingJoinPoint pjp) throws Throwable {
	System.out.println("环绕通知--开启事务..."+pjp.getSignature().getName());
	Object reobj = pjp.proceed();
	System.out.println("环绕通知--提交事务..."+pjp.getSignature().getName());
}

第8步:声明异常通知

<!-- 异常通知 throwing 异常方法名-->
<aop:after-throwing method="myAfterThrowing" pointcut-ref="mypointcut" throwing="e"></aop:after-throwing>

java

//自定义异常通知
@AfterThrowing(value = "myPoinCut()",throwing = "e")
public void myAfterThrowing(JoinPoint jp,Throwable e){
	System.out.println("异常通知:" + jp.getSignature().getName() + "===" + e.getMessage());
}

第9步:声明最终通知

<!-- 最终通知 -->
<aop:after method="myAfter" pointcut-ref="mypointcut"></aop:after>
//自定义最终通知
@After(value = "myPoinCut()")
public void myAfter(){
	System.out.println("最终通知--");
}

# 注解配置总

1.目标类

//目标类接口
package com.zh.service;

public interface IUserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}
//目标类实现
@Service("userService")
public class UserServiceImpl implements IUserService{

    @Override
    public void addUser() {
        System.out.println("添加用户");
        //int i = 10/0;
    }

    @Override
    public void updateUser() {
        System.out.println("更新用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

2.切面类

@Component
@Aspect
public class MyAspect{
    //声明公共切入点
    @Pointcut("execution(* com.zh.service.*.*(..))")
    public void myPoinCut(){
    }

    //自定义的前置通知
    //@Before("execution(* com.zh.service.*.*(..))")
    @Before(value = "myPoinCut()")
    public void myBefore(JoinPoint jp){
        System.out.println("前置通知--"+jp.getSignature().getName());
    }

    //自定义的后置通知
    @AfterReturning(value = "myPoinCut()",returning = "retValue")
    public void myAfterReturning(JoinPoint jp, Object retValue){
        System.out.println("后置通知--"+jp.getSignature().getName());
        System.out.println("返回值:" + retValue);
    }

    //自定义环绕通知
    @Around(value = "myPoinCut()")
    public void myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕通知--开启事务..."+pjp.getSignature().getName());
        Object reobj = pjp.proceed();
        System.out.println("环绕通知--提交事务..."+pjp.getSignature().getName());
    }

    //自定义异常通知
    @AfterThrowing(value = "myPoinCut()",throwing = "e")
    public void myAfterThrowing(JoinPoint jp,Throwable e){
        System.out.println("异常通知:" + jp.getSignature().getName() + "===" + e.getMessage());
    }

    //自定义最终通知
    @After(value = "myPoinCut()")
    public void myAfter(){
        System.out.println("最终通知--");
    }
}

3.配置文件

<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: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/aop
                        http://www.springframework.org/schema/aop/spring-aop.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 扫描注解 -->
    <context:component-scan base-package="com.zh"></context:component-scan>
    <!-- 确定AOP注解生效 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

4.测试类

public class lesson11 {
    @Test
    public void test1(){
        //AspectJ全自动代理
        ApplicationContext context = new ClassPathXmlApplicationContext("beans11.xml");

        //直接创建userService
        IUserService userService = (IUserService) context.getBean("userService");
        userService.addUser();
    }
}

控制台

环绕通知--开启事务...addUser
前置通知--addUser
添加用户
环绕通知--提交事务...addUser
最终通知--
后置通知--addUser
返回值:null

# 事务管理

# AOP的事务配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 获取db.properties类路径 -->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <!-- 配置c3p0数据源对象 -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${driverClass}"></property>
        <property name="jdbcUrl" value="${jdbcUrl}"></property>
        <property name="user" value="${user}"></property>
        <property name="password" value="${password}"></property>
    </bean>

    <!-- 配置dao -->
    <bean name="accountDao" class="com.zh.dao.Impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置service -->
    <bean name="accountService" class="com.zh.service.Impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
<!-- ................................................................................. -->
    <!-- 配置事务管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--配置dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 基于AOP事务配置 -->
    <!-- 1.配置通知
        propagation 传播行为
        isolation 隔离级别
		transaction-manager事务管理器
    -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="transer" isolation="DEFAULT" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!-- 2.切面点关联 -->
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.zh.service.*.*(..))"></aop:advisor>
    </aop:config>
</beans>

java

public class lesson04 {
    @Test
    public void test1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans5.xml");
        //获取service
        IAccountService accountService = (IAccountService) context.getBean("accountService");
        //转账
        accountService.transfer("jack","rose",100);
    }
}

控制台

1	jack	9400
2	rose	10600

# 注解的事务配置

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 获取db.properties类路径 -->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <!-- 配置c3p0数据源对象 -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${driverClass}"></property>
        <property name="jdbcUrl" value="${jdbcUrl}"></property>
        <property name="user" value="${user}"></property>
        <property name="password" value="${password}"></property>
    </bean>

    <!-- 配置dao -->
    <bean name="accountDao" class="com.zh.dao.Impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置service -->
    <bean name="accountService" class="com.zh.service.Impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
<!-- ................................................................................. -->
    <!-- 注解事务管理器配置 -->
    <!-- 1.配置事务管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--配置dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 2.开始注解事务驱动 -->
    <tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
</beans>

java

//@Transactional配置在类上所有方法有效,可以配置到方法上,默认配置可以省略参数
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
public class AccountServiceImpl implements IAccountService{
    public IAccountDao accountDao;

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }
    @Override
    public void transfer(final String outer, final String innter, final Integer money) {
        //扣钱
        accountDao.out(outer,money);
        //int i = 10/0;
        //进帐
        accountDao.in(innter,money);
    }
}

java

public class lesson04 {
    @Test
    public void test1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans6.xml");
       //获取代理类
        IAccountService accountService = (IAccountService) context.getBean("accountService");
        //转账
        accountService.transfer("jack","rose",100);
    }
}

控制台

1	jack	9400
2	rose	10600

# Spring整合mybatis

# 1.创建Model

package bean;
 
public class User {
    int id;
    String name;
    int age;
    String sex;
    String school;
 	...get set 
    @Override
    public String toString() {
        return ("姓名:"+name+"\n年龄:"+age+"\n性别"+sex+"\n学校"+school);
    }
}

# 2.写出这个类的映射接口

package dao;
 
import bean.User;
 
public interface IUser {
    User getUserByID (int id);
}

# 3.写出这个类的映射Mapper文件

<?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="dao.IUser">
    <select id="getUserByID" resultType="User" parameterType="int">
        SELECT * from user where id = #{id}
    </select>
</mapper>

# 4.准备mysql.properteis的参数配置文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=UTF-8
jdbc.uid=root
jdbc.password=123456

# 5.mybatis配置文件

mybatis文件与之前不同,之前实在mybatis-config.xml中配置数据库连接的,现在要把这些放在spring的配置文件中,所以mybatis配置文件中只写类的别名和引用的Mapper

<?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>
        <typeAlias alias="User" type="bean.User"/>
    </typeAliases>

    <mappers>
        <!-- // power by http://www.yiibai.com -->
        <mapper resource="xml/User.xml"/>
    </mappers>
 
</configuration>

# 6.spring配置文件

在**spring-config.xml中,**我们要配置数据库连接池,和sqlSessionFactory对象,以及UserMapper对象。

  • sqlSessionFactory中引用mybatis-config.xml文件
  • userMapper中标明要实现的接口
<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        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/context
       http://www.springframework.org/schema/context/spring-context-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
 
    <!--表明引用的参数配置文件是mysql-local.properties-->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>
                    mysql-local.properties
                </value>
            </list>
        </property>
    </bean>
 
 
    <!--数据库连接池-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.uid}"/>
        <property name="password" value="${jdbc.password}"/>
        <!-- 初始连接池大小 -->
        <property name="initialPoolSize" value="10"/>
        <!-- 连接池中连接最小个数 -->
        <property name="minPoolSize" value="5"/>
        <property name="maxPoolSize" value="20"/>
     </bean>
 
 
    <!-- 配置SqlSessionFactory对象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入数据库连接池 -->
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="mybatis-spring-config.xml"/> 
    </bean>
 
    <!--配置userMapper对象-->
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="dao.IUser"/>
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
 
</beans>

# 7.测试

package bean;
 
import dao.IUser;
import org.apache.ibatis.session.SqlSession;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class DemoTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        IUser userMapper = (IUser)context.getBean("userMapper");
        User user = userMapper.getUserByID(2);
        System.out.println(user);
 
    }
 
}