欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring回顾学习(二)spring中的动态代理

程序员文章站 2022-06-09 09:15:47
...

Spring框架中的动态代理

 @Test
    public void test1() {
//创建目标对象
        TargetInterface targetInterface = new TargetImpl();
        //创建代理对象(如果目标对象实现了接口那么第一个参数是需要代理的对象的类的类加载器,第二个参数是代理所实现的所有接口,第三个参数是一个匿名内部类)
        TargetInterface ti = (TargetInterface) Proxy.newProxyInstance(TargetImpl.class.getClassLoader(), TargetImpl.class.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("在本方法前增强");
                //调用目标对象需要增强的方法~~这样默认增强的是所有方法,如何选中其中的某一个方法~~
                method.invoke(targetInterface, args);
              //  targetInterface.save();()
                System.out.println("在方法后增强");
                //这里的返回值就是需要增强的方法的返回值(如果有的话)
                return null;
            }
        });
        ti.save();
        System.out.println("========");
        ti.delete();

    }

导入Spring开发的基本坐标在maven项目的pom文件中的project标签内

<!--第一步导入spring版本号,必须和当前spring的版本号一致 -->
<properties>
	<spring.version>5.0.5.RELEASE</spring.version>	
</properties>
<dependcies>
	<dependency>
    	<groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependcies>

编写Dao接口和实现类

创建Spring核心配置文件

在resource下新建一个spring的xml文件

在spring配置文件中配置UserDaoImpl

在beans标签中添加bean标签 添加bean标签的id属性和class属性class属性的内容是需要交给spring容器管理的类的相对于java这个包的路径,

使用spring的api获得bean实例

在测试类中使用springapi获取实例,使用ClassPathXmlApplicationContext()传入参数是你刚才创建的resource中的spring的资源文件,使用ApplicationContext接收对象

调用对象的getbean方法传入配置在xml中的bean标签的id 那么spring容器就会根据这个getbean方法传入的id找到配置文件中所属的id(id唯一),再通过这个id后面对应的class路径找到这个类,通过类的无参构造方法创建这个类的对象 ,所以我们就可以用这个对象直接调用对象中的方法

Spring配置文件

Bean标签的基本配置

基本属性:id Bean实例在Spring容器中的唯一标识

​ class Bean的全限定名(这个类的相对路径从java包开始算

​ scope:指对象的作用范围

取值范围 说明
singleton 默认值,单例的
prototype 多例的
request WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
session WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
global session WEB 项目中,应用在 Portlet 环境,如果没有 Portlet 环境那么globalSession 相当于 session

1)当scope的取值为singleton时

​ Bean的实例化个数:1个

​ Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例

​ Bean的生命周期:

对象创建:当应用加载,创建容器时,对象就被创建了

对象运行:只要容器在,对象一直活着

对象销毁:当应用卸载,销毁容器时,对象就被销毁了

2)当scope的取值为prototype时

​ Bean的实例化个数:多个

​ Bean的实例化时机:当调用getBean()方法时实例化Bean

对象创建:当使用对象时,创建新的对象实例

对象运行:只要对象在使用中,就一直活着

对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了

Bean的生命周期配置

init-method:指定类中的初始化方法名称

destroy-method:指定类中销毁方法名称

Bean实例化的三种方式

1、无参构造

<bean id = "aa" class="com.lzh.dao.impl.UserDaoImpl" />

2、工厂静态方法实例化

public class StaticFactoryBean{
	public static User Dao createUserDao(){
        return new UserDaoImpl():
    }
}

<bean id = "userDao" class="com.lzh.factory.StaticFactorBean"
      factory-method="createUserDao"/>

3、工厂非静态方法返回Bean的实例

<bean id = "factoryBean" class = "com.lzh.factory.DynamicFactoryBean " />
<bean id "userDao" factory-bean="factoryBean"
      factory-method="createUserDao"/>

将第一个bean标签和第二个建立依赖关系

bean标签配置好之后在测试类中创建ClassPathXmlApplicationContext的对象使用他的接口ApplicationContext来接收

Bean的依赖注入

①创建 UserService,UserService 内部在调用 UserDao的save() 方法

public class UserServiceImpl implements UserService {
	@Override
	public void save() {
         ApplicationContext applicationContext = new 
                 ClassPathXmlApplicationContext("applicationContext.xml");       	           UserDao userDao = (UserDao) applicationContext.getBean("userDao");	
          userDao.save();
 	}
 }

②将 UserServiceImpl 的创建权交给 Spring

<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>

③从 Spring 容器中获得 UserService 进行操作

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.save();

Bean的依赖注入概念

​ 依赖注入(Dependency Injection):是Spring框架核心IOC(控制反转)的具体实现。

​ 将创建对象的控股职权交给spring容器 IOC解耦仅仅是降低依赖关系并不能完全消除

Bean的依赖注入方式

①构造方法

​ 创建有参构造

public class UserServiceImpl implements UserService {
@Override
public void save() {
ApplicationContext applicationContext = new 
                 ClassPathXmlApplicationContext("applicationContext.xml");       UserDao userDao = (UserDao) applicationContext.getBean("userDao");    
          userDao.save();
    }
 }

​ 配置Spring容器调用有参构造时进行注入

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">      		   	<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>

②set方法

​ 在UserServiceImpl中添加setUserDao方法

public class UserServiceImpl implements UserService {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;  
        } 
    @Override    
    public void save() {      
   		 userDao.save();
	}
}

​ 配置Spring容器调用set方法进行注入

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
	<property name="userDao"~~这个不是上边的id而是get方法后面的名字并将首字母小写~~ ref="userDao"/>
</bean>

set方法:P命名空间注入

​ P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下:

​ 首先,需要引入P命名空间:

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

其次,需要修改注入方式

<bean id="userService" class="com.itheima.service.impl.UserServiceImpl" p:userDao-
 ref="userDao"/>

Bean的依赖注入的数据类型

上面的操作,都是注入的引用Bean,处了对象的引用可以注入,普通数据类型,集合等都可以在容器中进行注入。

注入数据的三种数据类型

普通数据类型

引用数据类型

集合数据类型

其中引用数据类型,此处就不再赘述了,之前的操作都是对UserDao对象的引用进行注入的,下面将以set方法注入为例,演示普通数据类型和集合数据类型的注入。

Bean的依赖注入的数据类型(总的来说就是使用property标签进行注入)

(1)普通数据类型的注入

public class UserDaoImpl implements UserDao {
private String company;
    private int age;
    public void setCompany(String company) {
        this.company = company;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void save() {
        System.out.println(company+"==="+age);
        System.out.println("UserDao save method running....");   
    }
}

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
    <property name="company" value="传智播客"></property>
    <property name="age" value="15"></property>
</bean>

(2)集合数据类型(List)的注入

public class UserDaoImpl implements UserDao {
	private List<String> strList;
	public void setStrList(List<String> strList) {
		this.strList = strList;
	}
	public void save() {
        System.out.println(strList);
        System.out.println("UserDao save method running....");
	}
}
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
    <property name="strList">
        <list>
            <value>aaa</value>
            <value>bbb</value>
            <value>ccc</value>
        </list>
    </property>
</bean>

(3)集合数据类型(List)的注入

public class UserDaoImpl implements UserDao {
	private List<User> userList;
	public void setUserList(List<User> userList) {
	this.userList = userList;  
 }
public void save() {
	System.out.println(userList);
	System.out.println("UserDao save method running....");
	}
}
<bean id="u1" class="com.itheima.domain.User"/>
<bean id="u2" class="com.itheima.domain.User"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
    <property name="userList">
        <list>
            <bean class="com.itheima.domain.User"/>
            <bean class="com.itheima.domain.User"/>
            <ref bean="u1"/>
            <ref bean="u2"/>       
        </list>
    </property>
</bean>

(4)集合数据类型( Map<String,User> )的注入

public class UserDaoImpl implements UserDao {
    private Map<String,User> userMap;
    public void setUserMap(Map<String, User> userMap) {
    this.userMap = userMap;
    }    
public void save() {      
	System.out.println(userMap);
	System.out.println("UserDao save method running....");
	}
}
<bean id="u1" class="com.itheima.domain.User"/>
<bean id="u2" class="com.itheima.domain.User"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
    <property name="userMap">
        <map>            
            <entry key="user1" value-ref="u1"/>
            <entry key="user2" value-ref="u2"/>
        </map>
    </property>
</bean>

(5)集合数据类型(Properties)的注入

public class UserDaoImpl implements UserDao {
    private Properties properties;
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
	public void save() {
		System.out.println(properties);
		System.out.println("UserDao save method running....");
	}
}
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
    <property name="properties">
        <props>
            <prop key="p1">aaa</prop>
            <prop key="p2">bbb</prop> 
            <prop key="p3">ccc</prop>
        </props>
    </property>
</bean>

引入其他配置文件(分模块开发)

实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他配置文件中,而在Spring主配置文件通过import标签进行加载

<import resource="applicationContext-xxx.xml"/>

spring相关API

ApplicationContext的继承体系

applicationContext:接口类型,代表应用上下文,可以通过其实例获得 Spring 容器中的 Bean 对象

ApplicationContext的实现类

1)ClassPathXmlApplicationContext

​ 它是从类的根路径下加载配置文件 推荐使用这种

2)FileSystemXmlApplicationContext

​ 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。

3)AnnotationConfigApplicationContext

​ 当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

4.3 getBean()方法使用

public Object getBean(String name) throws BeansException {  
	assertBeanFactoryActive();   
	return getBeanFactory().getBean(name);
}
public <T> T getBean(Class<T> requiredType) throws BeansException {   			    	assertBeanFactoryActive();
	return getBeanFactory().getBean(requiredType);
}

其中,当参数的数据类型是字符串时,表示根据Bean的id从容器中获得Bean实例,返回是Object,需要强转。

当参数的数据类型是Class类型时,表示根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错

getBean()方法使用

ApplicationContext applicationContext = new 
            ClassPathXmlApplicationContext("applicationContext.xml");
  UserService userService1 = (UserService) applicationContext.getBean("userService");
  UserService userService2 = applicationContext.getBean(UserService.class);
相关标签: 标签