SSM-Spring(学习笔记)

Spring

1、spring

1.1、优点

spring是一个开源的免费的框架(rongq)

spring是一个轻量级的、非入侵式的框架

控制反转(IOC),面向切面编程(AOP)

支持事务的处理,对框架整合的支持

1.2、spring组成及扩展

2、IOC本质推导

使用maven新建一个项目

添加一个UerDao接口

public interface UserDao {
    void getUser();
}

添加一个UserDao实现类

public class UserDaoImpl  implements UserDao{
    @Override
    public void getUser() {
        System.out.println("获取用户数据");
    }
}

新建一个UserService接口

public interface UserService {
    void getUser();
}

添加一个UserService实现类

import com.heng.dao.UserDao;
import com.heng.dao.UserDaoImpl;
//实现UserService接口
public class UserServiceImpl implements UserService {

    private UserDao userdao = new UserDaoImpl();
    @Override
    public void getUser() {
        //调用dao层方法
          userdao.getUser();
    }
}

添加测试类,模拟controller

import com.heng.dao.UserDao;
import com.heng.dao.UserDaoImpl;
//实现UserService接口
public class UserServiceImpl implements UserService {

    private UserDao userdao = new UserDaoImpl();
    @Override
    public void getUser() {
        //调用dao层方法
          userdao.getUser();
    }
}

紧接着我们要去使用MySql的话 , 我们就需要去UserService实现类里面修改对应的实现 :

package com.heng.dao;

public class UserDaoMySqlIpml implements UserDao {
    @Override
    public void getUser() {
        System.out.println("获取MySql用户数据");
    }
}

这时又要在测试类写一个测试

    private UserDao userDao = new UserDaoMySqlIpml();  // 修改实例对象

    @Override
    public void getUser() {
        userDao.getUser(); // 调用Dao层方法
    }
}

如果这样的需求很多,这时候这种设计就会耦合很高,不适合快速开发

方法改进

UserService的实现类不是直接去New一个新的实例,而是留出set接口,让调用者决定选择哪个具体的Dao实现,当然这其中有多态的思想在里面:

public class UserServiceImpl implements UserService {
    
        private UserDao userDao;
        // 利用set方法实现
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
        @Override
        public void getUser() {
            userDao.getUser();
        }
    }

接着测试类

public class MyTest {
    public static void main(String[] args) {
        UserService service = new UserServiceImpl();
        ((UserServiceImpl) service).setUserDao(new UserDaoMySqlIpml());
        service.getUser();
    }
// print "获取MySql用户数据"

}

虽然只是一个简单的例子,但其中包含的设计思想确实比较高级的:

  • 以前所有东西都是由程序去进行控制创建
  • 而现在使用了set注入,主动权交给了调用者
  • 程序不用去管怎么创建,而是专注于业务逻辑的实现,耦合性大大降低 . 这也就是IOC的原型 。
IOC本质

img

**

控制反转(IOC)是一种设计思想,依赖注入(DI)是实现IOC的一种方式。在没有IOC的程序中,我们使用面向对象编程,对象的创建和对象之间的依赖完全硬编码在程序中,对象的创建由程序自己控制,控制反转后对象的创建转移给第三方,也就是“获得依赖对象的方式反转了”。

依赖注入

IOC的另外的名字叫做依赖注入(Dependency Injection),所谓的依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦

3、springhello

1、新建一个maven包,添加UserDao类
package com.heng.dao;

public class UserDao {
    private String string;

    public UserDao() {
    }

    public String getString() {
        return string;
    }

    public void setString(String string) {
        this.string = string;
    }

    @Override
    public String toString() {
        return "UserDao{" +
                "string='" + string + '\'' +
                '}';
    }
}
2、在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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 使用spring创建对象-->
<!--
       类型 变量名 = new 类型()
       UerDao hello = new UserDap();
       id就是hello 然后class就是全路径下的包
       name就是实例化后的变量
       value就是把spring赋给string这个变量
-->
    <bean id="hello" class="com.heng.dao.UserDao">
        <property name="string" value="spring"/>
    </bean>

</beans>
3、新建测试类
import com.heng.dao.UserDao;
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");
        //将id传入
     UserDao hello = (UserDao) Context.getBean("hello");
        System.out.println(hello.toString());
    }
}
4、?思考:

在上面的bean.xml里面,是没有实例化对象的,

那么是谁创建了对象了?

是spring

那对象的属性是怎么设置的?

对象的属性是由spring容器设置的

这个过程就叫控制反转

控制:谁来和控制对象的创建,传统应用程序的对象是由程序本身控制创建的,例如Hello hello = new Hello();使用spring后,对象是由spring创建的。

反转:程序本身不创建对象,而变成被动的接收对象。

依赖注入:就是利用set方法来进行注入的

IOC是一种编程思想,由主动的编程变成被动的接受。

4、IOC创建对象方式

1、调用无参数构造器创建对象
1.1、User类
package com.heng.pojo;

public class User {
    private String name;

    public User() {
        System.out.println("这是无参构造");
    }

    public String getName() {
        return name;
    }

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


   public void show(){
        System.out.println("name"+name);
    }
}
1.2、beas.xml
<bean id="user" class="com.heng.pojo.User">
</bean>
1.3、Test类
import com.heng.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");
    }
}
2、调用有参数构造器创建对象
2.1、User类
在原来的User类上添加一个有参构造方法
public User(String name ){
    System.out.println("这是有参构造");
    this.name=name;
}
2.2、beans.xml
<!--    调用有参构造-->
<!--    方法一 -->
    <bean id="user" class="com.heng.pojo.User">
        <!--index表示参数下标,从左到右,上面的name就是0,如果有id就是1 -->
            <constructor-arg value="呐喊" index="0" type="java.lang.String">
            </constructor-arg>
    </bean>
<!--  方法二   -->
    <bean id="name" class="java.lang.String">
        <constructor-arg value="呐喊"></constructor-arg>
    </bean>
    <bean id="user" class="com.heng.pojo.User">
        <constructor-arg index="0" type="java.lang.String" ref="name">

        </constructor-arg>
    </bean>
2.3、Test
import com.heng.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");
        System.out.println(user.getName());
    }
}

总结:在配置文件加载的时候,容器中的管理对象就已经初始化了

5、Spring配置说明

5.1、别名(和MyBatis的别名意思一样)
<!--添加别名就是换个名字,用添加的名字也可以获取对象 -->
<alias name ="user" alias="usernew"
5.2、bean的配置
<!--
      bean的唯一标识符:id,和对象一样
      class:就是bean的全类型:包名+类型名。
      name:就是别名。但是这个name更加好用,可以同时取多个别名
-->
    </bean>
    <bean id="user" class="com.heng.pojo.User" name="user2,user3">
        <property name="name" value="name"/>
    </bean>
5.3、import

适用于团队开发,在有多个beans时可以通过import引用,然后汇总到一个ApplicationContenxt.xml上。

<import resource="beans1.xml" />
<import resource="beans2.xml" />
<import resource="beans3.xml" />

6、DI依赖注入环境

6.1、构造器注入

在IOC创建对象时学过了

6.2、Set方法注入【重点】

依赖注入:Set注入

依赖:bean对象的创建依赖于容器中

注入:bean对象的所有属性,由容器注入

Student类

package com.heng.pojo;

import java.util.*;

public class Student {
    
    private String name;
    
    private Address address;
    
    private String[] books;
    
    private List<String> hobby;
    
    private Map<String,String> card;
    
    private Set<String> games;
    
    private Properties info;

    public Student() {
    }

    public Student(String name, Address address, String[] books, List<String> hobby, Map<String,String> card, Set<String> games, Properties info) {
        this.name = name;
        this.address = address;
        this.books = books;
        this.hobby = hobby;
        this.card = card;
        this.games = games;
        this.info = 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> getHobby() {
        return hobby;
    }

    public void setHobby(List<String> hobby) {
        this.hobby = hobby;
    }

    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 Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address +
                ", books=" + Arrays.toString(books) +
                ", hobby=" + hobby +
                ", card=" + card +
                ", games=" + games +
                ", info=" + info +
                '}';
    }

}

Address类

package com.heng.pojo;

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address+ '\'' +
                '}';
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.heng.pojo.Address"/>


    <bean id="student" class="com.heng.pojo.Student">
<!--          第一种,普通值注入    -->
        <property name="name" value="呐喊"/>
<!--              bean注入               -->
        <property name="address" ref="address"/>
<!--              数组注入-->
        <property name="books">
            <array>
                    <value>java如此简单</value>
                    <value>Spring</value>
                    <value>SpringBoot</value>
            </array>
        </property>
<!--               list         -->
<property name="hobby">
    <list>
        <value>打球</value>
        <value>听歌</value>
        <value>看电影</value>
    </list>
</property>
        <property name="card">
            <map>
                <entry key="身份证" value="12313213654"></entry>
                <entry key="学生证" value="1321321465465"></entry>
            </map>
        </property>
        <property name="games">
            <set>
                <value>LOL</value>
                <value>王者荣耀</value>
                <value>和平精英</value>
            </set>
        </property>
        <property name="info">
          <props>
              <prop key="driver">2015</prop>
              <prop key="url"></prop>
              <prop key="username">呐喊</prop>
              <prop key="password">123456</prop>
          </props>
        </property>
    </bean>
</beans>

测试类

import com.heng.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='null'},
 * books=[java如此简单, Spring, SpringBoot],
 * hobby=[打球, 听歌, 看电影],
 * card={身份证=12313213654, 学生证=1321321465465},
 * games=[LOL, 王者荣耀, 和平精英], i
 * nfo={password=123456, driver=2015, url=男, username=呐喊}}
 */
}

7、c命名和p命名空间注入

7.1、p命名

使用这两个命名的时候,需要在头文件上加入以下两个链接

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

编写xml

<bean id="user" class=p"com.heng.dao.User" p:name="呐喊" p:id="123456">
</bean>

测试类

@Test
public void getUser(){
   ApplicationContext Context = new ClassPathXmlApplicationContext("beans.xml");
   User user =  Context.getBean("user",User.class);
    System.out.println(ucser.toString());

}

其实和传统的值注入,可以看出,并不需要写太多的代码,用p:代替原来的properties,更加简洁

7.2、c命名

编写xml

<!--   传统的constructor-arg通过构造方法注入的bean定义-->
    <bean id="user1" class="com.heng.dao.User">
        <constructor-arg index="0" value="呐喊"/>
        <constructor-arg index="1" value="123456"/>
    </bean>
<!--    C命名空间通过构造方法注入的bean定义-->
    <bean id="user2" class="com.heng.dao.User" c:_0="呐喊" c:_1="1234567"> </bean>

由上面可以知道,和传统的注入代码简洁许多

8、Bean

8.1、自动装配bean

在Spring框架里面是使用set方法和构造方法进行注入的,但是bean对象多了以后这样的注入工作就显得麻烦,还有就是xml文件也会变得很大很杂乱,所以为了简化xml配置文件,提高开发效率我们可以使用autowire

优点

自动装配可以大大地减少属性和构造器参数的指派。

自动装配也可以在解析对象时更新配置。

在spring中有三种配置方式:

1、在xml中显示的配置

2、在java中显示配置

3、隐式的自动装配

8.2、编写实体类

下面的是byname

byname:会自动在容器的上下文中查找,和自己set方法后面匹配的bean id;

byTyper:会自动在容器的上下文中查找,和自己类型相同的bean id

Person类

package com.heng.pojo;

public class Person {
    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 "Person{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

Cat

package com.heng.pojo;

public class Cat {
    public void shout(){
        System.out.println("我是小猫,喵");
    }
}

Dog

package com.heng.pojo;

public class Dog {
    public void shout(){
        System.out.println("我是小狗,汪");
    }
}

xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="cat22" class="com.heng.pojo.Cat"></bean>
    <bean id="dog22" class="com.heng.pojo.Dog"></bean>
<!--
       byname:会自动在容器的上下文中查找,和自己set方法后面匹配的bean id;
       byTyper:会自动在容器的上下文中查找,和自己类型相同的bean id。
-->
    <bean id="person" class="com.heng.pojo.Person" autowire="byType">
        <property name="name" value="呐喊">
        </property>
   <!--       传统的值注入-->
   <!--    <property name="dog" ref="dog"></property>-->
   <!--    <property name="cat" ref="cat" ></property>-->
</bean>
</beans>

测试类

import com.heng.pojo.Person;
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");
       Person person = (Person) Context.getBean("person");
        System.out.println(person.getName());
        person.getDog().shout();
        person.getCat().shout();
    }
//             呐喊
//            我是小狗,汪 
//            我是小猫,喵

}

9、注解实现自动装配

9.1、导入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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <!--开启注解支持-->
    <context:annotation-config/>
    <!--只需要配置id和类型即可-->
            <bean id="cat" class="com.heng.pojo.Cat"></bean>
            <bean id="dog" class="com.heng.pojo.Dog"></bean>
            <bean id="person" class="com.heng.pojo.Person"></bean>


</beans>

注意,在导入xml时一定要开启注解支持,要不然是用不了!

9.2、实体类
package com.heng.pojo;

import org.springframework.beans.factory.annotation.Autowired;

public class Person {
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;

    private String name;

    public Cat getCat() {
        return cat;
    }
@Autowired
    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }
@Autowired
    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 "Person{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

另外两个实体类和上面的两个cat和dog一样

import com.heng.pojo.Person;
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");
       Person person = (Person) Context.getBean("person");
        person.getDog().shout();
        person.getCat().shout();
    }

//            我是小狗,汪
//            我是小猫,喵

}

@Autowired

直接在属性上使用即可,也可以在set方法上使用。

使用Autowired就可以不用去写set方法了,前面我直接在set方法上用Autowired注解了。前提是你这个自动装配的属性在ioc容器中存在。

9.3、@Autowired(required=false)

如果显示定义了Autowired的required的属性为false,数码这个对象可以为null。否则不允许为空。

@Autowired(required = false)
private Cat cat;
@Autowired
private Dog dog;

private String name;

当配置文件中的id不唯一时,可以通过@resource(name=“id”)来指定唯一id

10、spring注解开发。

导入常用依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

引入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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!--指定的包扫描,这个包下的注解才会生效-->
    <context:component-scan base-package="com.heng.pojo"/>
    <!--开启注解支持-->
    <context:annotation-config/>
</beans>

组件

@Conponent 扫描

@Value 赋值


/**
 *  @Conponent 相当于  <bean id="user" class="com.heng.pojo.User"></bean>
 */
@Component
public class User {
   
    public String name;
    @Value("呐喊")
    /**
     *  相当于<property name="name" value="呐喊"></property>
     */
    public void setName(String name) {
        this.name = name;
    }
}
10.1、使用java Config 进行配置

在这个知识点里面需要了解的是,不需要使用xml进行配置了,都交给java进行配置。

首先还是要先引入头文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <!--指定的包扫描,这个包下的注解才会生效-->
    <context:component-scan base-package="com.heng.pojo"/>
    <!--开启注解支持-->
    <context:annotation-config/>

</bea

然后编写实体类

package com.heng.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//扫描配置
@Component
public class Person {

    private String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    //注入值
    @Value("呐喊")
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

然后就是配置类

其实原来的xml配置都在这了,只不过更加的方便,由注解进行配置(Spring Boot 就是这样的)

package com.heng.pojo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//表示这个类为javaconfig 类
//@Configuration 代表的是这是一个配置类。即applicationContect.xml
@Configuration
public class MyConfig {
    /**
     * 这个bean相当于原来的配置文件中的bean标签
     * 这个方法的名相当于原来的id
     * 返回的方法名,相当于原来的class
     * @return
     */
    @Bean
    public Person getPerson(){
        return new Person();
    }
}

测试类

import com.heng.pojo.MyConfig;
import com.heng.pojo.Person;
import org.springframework.context.ApplicationContext;
        import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext Context = new AnnotationConfigApplicationContext(MyConfig.class);
        Person getPerson = (Person) Context.getBean("getPerson");
        System.out.println(getPerson.getName());
    }
}

11、代理模式

代理模式的分类

静态代理

动态代理

11.1、静态代理

静态代理用我的话来来说就是

包租婆–》中介–》租房子的人

中介就是静态代理。包租婆找到中介然后把房子代理给他,就可以不管了,然后租房的人找中介来租房子。

静态代理说白了就是在程序运行前就已经存在代理类的字节码文件,代理类和原始类的关系在运行前就已经确定

定义接口

package com.heng.demo1;
//定义接口
public interface IPerson {
    public abstract void sleep();
    public abstract void eat();

}

被代理类

package com.heng.demo1;

public class Peson implements IPerson{

    @Override
    public void sleep() {
        System.out.println("zzz```");
    }

    @Override
    public void eat() {
        System.out.println("吃饭中");

    }
}
package com.heng.demo1;


public class PersonProxy implements IPerson {
    private IPerson person;

    public PersonProxy(IPerson person) {
        this.person = person;
    }

    @Override
    public void sleep() {
        person.sleep();

    }

    @Override
    public void eat() {
        person.eat();
    }
}

测试类

import com.heng.demo1.IPerson;
import com.heng.demo1.PersonProxy;
import com.heng.demo1.Peson;

public class MyTest {
    public static void main(String[] args) {
        IPerson proxy = new PersonProxy(new Peson());
        proxy.sleep();
        proxy.eat();
    }



}

静态代理,后期维护代价太大,更加倾向于动态代理

11.2、动态代理

定义接口

package com.heng.deno03;

public interface UserService {
      public void add();
       public void delete();
       public void update();
       public void query();
}

实现接口

package com.heng.deno03;

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("查找了一个用户");
    }
}

动态主要机制是通过反射机制来实现的。实现InvocationHandler接口。

其实动态代理的主要代码是可以写死的。

和工具类一样

package com.heng.deno03;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyHandler 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 {
        Object result = method.invoke(target,args);
        return result;
    }
}

测试

package com.heng.deno03;

import com.heng.demo2.UserDao;
public class client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userDao = new UserServiceImpl();
        //代理角色,不存在
        ProxyHandler pih= new ProxyHandler();
        pih.setTarget(userDao);//设置要代理的对象
        //动态生成代理对象
       UserService proxy =(UserService) pih.getProxy();
        //调用实例
        proxy.add();
    }
}

12、AOP

1、AOP的基本概念

AOP(Aspect Oriented Programming)称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Tc7VFIc-1598706029470)(C:\Users\12920\AppData\Roaming\Typora\typora-user-images\image-20200829132123039.png)]

  • Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
  • Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。
  • Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
  • Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
  • Target(目标对象):织入 Advice 的目标对象.。
  • Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

了解完AOP之后,我们来看下怎么实现AOP吧

2、实现AOP(第一种)

导入依赖

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

新建一个接口和接口的实现类

package com.heng.service;

public interface UserService {
    void add();
    void delete();
    void update();
    void select();
}
package com.heng.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("选择了一个用户");
    }
}

接着我们要实现的是前置日志和后置日志

其实就是起到一个记录的作用,方便自己记录

package com.heng.Log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeLog implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}
package com.heng.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);
    }
}

接下来的就是最重点的xml配置项了

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

    <!--    注册bean-->
    <bean id="userService" class="com.heng.service.UserServiceImpl"/>
    <bean id="beforeLog" class="com.heng.Log.BeforeLog"/>
    <bean id="afterLog"  class="com.heng.Log.AfterLog"/>
    <!--    配置aop 导入aop的约束-->
    <aop:config>
        <!--        切入点 :execution(执行的位置)-->
        <aop:pointcut id="pointcut" expression="execution(* com.heng.service.UserServiceImpl.*(..))"/>
        <!--        执行环绕-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

测试类

import com.heng.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();
    }
}
3、实现AOP(第二种)

自定义类来实现

package com.heng.diy;

public class DiyPointcut {
    public void before(){
        System.out.println("----执行前---");
    }
    public void after(){
        System.out.println("---执行后---");
    }
}

然后配置

<!--     方法二 自定义类-->
    <bean id="diy" class="com.heng.diy.DiyPointcut"/>
    <aop:config>
<!--        自定义切面 ref:要引入的类-->
        <aop:aspect ref="diy">
<!--            切入点-->
            <aop:pointcut id="ponit" expression="execution(* com.heng.diy.DiyPointcut.*(..))"/>
<!--            通知-->
            <aop:before method="before" pointcut-ref="ponit"/>
            <aop:after method="after" pointcut-ref="ponit"/>
        </aop:aspect>
    </aop:config>

总结

其实和第一种方法实现的道理是一样的,只不过没有实现spring的API来实现而已,这个是自己定义了一个类,然后在配置那里,注册进去,然后通过切入点去到通知层面调用这个方法。

4、注解实现AOP

配置AOP

<!--    开启注解支持-->
   <aop:aspectj-autoproxy/>
<bean id="annotation" class="com.heng.aono.Annotation"/
package com.heng.aono;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//标注这个类是一个切面类
//@Component
@Aspect
public class Annotation {

    @Before("execution(* com.heng.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("----方法执行前---");
    }
    @After("execution(* com.heng.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("---方法执行后---");
    }
}

13、Mybatis整合

1、实现方式一

1.1、编写数据库源

      <!--数据源,其实就是使用spring的数据源来替换原来的mybatis连接数据库的配置-->
   <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
       <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
       <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
       <property name="username" value="root"/>
       <property name="password" value="123"/>
   </bean>

注意:

在这里的数据源其实就是我们在学mybatis时配置的数据源,直接可以拿来使用。

1.2、编写接口和实现类

接口类

package com.heng.dao;

import com.heng.pojo.User;

import java.util.List;

public interface UserMapper {
    public List<User> getUser();
 }

实现类

package com.heng.dao;

import com.heng.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl  implements UserMapper{
    //在原来我们所有的操作都用sqlSessionFactory实现,现在我们使用.SqlSessionTemplate
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<User> getUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.getUser();
    }


}

在spring中注册

<bean id="userMapper" class="com.heng.dao.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>

还有一个UserMapper.xml不要忘记!!

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.heng.dao.UserMapper">
    <select id="getUser" resultType="User">
        select * from mybatis.user;
    </select>

</mapper>

当然了,还有实体类(其实如果想偷懒的话可以导入lombot插件,用注解可以实现下面的代码)

package com.heng.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 + '\'' +
                '}';
    }
}
1.3、SqlSessionFactory SqlSession

在原来的mybatis时,我们是需要一个工具类来声明 SqlSessionFactory 和 SqlSession

但是在整合时直接就可以整合到spring的xml中。

package com.heng.util;

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;
public class Mybatis {
    public static SqlSessionFactory sqlSessionFactory;
        static {
            try {
                String resource = "Mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = (new SqlSessionFactoryBuilder()).build(inputStream);
            } catch (IOException var3) {
                var3.printStackTrace();
            }

        }
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

整合时

<!--sqlSessFactory,原来的要在一个工具类声明这个sqlSessFactory,现在直接在这里加入即可。-->
<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/heng/dao/UserMapper.xml"/>
</bean>
  <!--SqlSessionTemplate就是我们在mybatis使用的SqlSession,在这里注入SqlSessionTemplate就可以不用newSqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <!--    在这里的话,如果由set方法就不用ref注入了    -->
    <constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
1.6、测试
import com.heng.dao.UserMapper;
import com.heng.pojo.User;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;
public class MyTest {

    public static void main(String[] args) throws IOException {

       ApplicationContext Context = new ClassPathXmlApplicationContext("applicationContext.xml");
      UserMapper userMapper = (UserMapper) Context.getBean("userMapper");
        for (User user : userMapper.getUser()) {
            System.out.println(user);

        }
    }

}

附:

完整applicationContext

<?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">

      <!--数据源,其实就是使用spring的数据源来替换原来的mybatis连接数据库的配置-->
   <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
       <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
       <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
       <property name="username" value="root"/>
       <property name="password" value="123"/>
   </bean>
    <!--sqlSessFactory,原来的要在一个工具类声明这个sqlSessFactory,现在直接在这里加入即可。-->
    <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/heng/dao/UserMapper.xml"/>
    </bean>
      <!--SqlSessionTemplate就是我们在mybatis使用的SqlSession,在这里注入SqlSessionTemplate就可以不用newSqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--    在这里的话,如果由set方法就不用ref注入了    -->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    <bean id="userMapper" class="com.heng.dao.UserMapperImpl">
    <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>

er()) {
System.out.println(user);

    }
}

}


**附:**

完整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
                        http://www.springframework.org/schema/beans/spring-beans.xsd">

      <!--数据源,其实就是使用spring的数据源来替换原来的mybatis连接数据库的配置-->
   <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
       <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
       <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
       <property name="username" value="root"/>
       <property name="password" value="123"/>
   </bean>
    <!--sqlSessFactory,原来的要在一个工具类声明这个sqlSessFactory,现在直接在这里加入即可。-->
    <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/heng/dao/UserMapper.xml"/>
    </bean>
      <!--SqlSessionTemplate就是我们在mybatis使用的SqlSession,在这里注入SqlSessionTemplate就可以不用newSqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--    在这里的话,如果由set方法就不用ref注入了    -->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    <bean id="userMapper" class="com.heng.dao.UserMapperImpl">
    <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>

其实还有一个整合方式,感兴趣可以去官方文档看一下,比上面的简单,但是方法只要懂一个即可,其它的就可以旁类触痛了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值