Giter Site home page Giter Site logo

learnspringblog's People

Stargazers

 avatar

Watchers

 avatar

learnspringblog's Issues

Spring注入参数

Spring注入参数


  1. 注入基本类型值
  2. 注入bean
  3. 内部bean
  4. null值
  5. 级联属性
  6. 集合类型属性
package com.java1234.entity;

public class Dog {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
package com.java1234.entity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class People {
	private int id;
	private String name;
	private int age;
	private Dog dog;
	private List<String> hobbies=new ArrayList<String>();
	private Set<String> loves=new HashSet<String>();
	private Map<String,String> works=new HashMap<String,String>();
	private Properties addresses=new Properties();
	
	public People() {
		super();
	}
	public People(int id, String name, int age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}

	public Set<String> getLoves() {
		return loves;
	}
	public void setLoves(Set<String> loves) {
		this.loves = loves;
	}
	public List<String> getHobbies() {
		return hobbies;
	}
	public void setHobbies(List<String> hobbies) {
		this.hobbies = hobbies;
	}
	public Map<String, String> getWorks() {
		return works;
	}
	public void setWorks(Map<String, String> works) {
		this.works = works;
	}
	public Properties getAddresses() {
		return addresses;
	}
	public void setAddresses(Properties addresses) {
		this.addresses = addresses;
	}
	public Dog getDog() {
		return dog;
	}
	public void setDog(Dog dog) {
		this.dog = dog;
	}
	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 int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "People [id=" + id + ", name=" + name + ", age=" + age
				+ ", dog=" + dog + ", hobbies=" + hobbies + ", loves=" + loves
				+ ", works=" + works + ", addresses=" + addresses + "]";
	}
}

来看bean

1. 注入基本类型值

最简单的,注入基本类型。

    <bean id="people1" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
	</bean>

2. 注入bean

我们给people2注入的不是普通的属性,是一个bean——dog1。
ref="dog1"表示引用的是一个bean,不再是value。
这是spring管理的bean之间的嵌套。

    <bean id="dog1" class="com.java1234.entity.Dog">
		<property name="name" value="Jack"></property>
	</bean>
	
	<bean id="people2" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
		<property name="dog" ref="dog1"></property>
	</bean>

3. 内部bean注入

现在这个dog1即可以被people1引用也可以被people2引用,我们现在要一个新的狗,只能被一个people引用。
我们直接在bean内部注入属性。这个“内部”顾名思义,很好理解。

    <bean id="people3" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
		<property name="dog">
			<bean class="com.java1234.entity.Dog">
				<property name="name" value="Tom"></property>
			</bean>
		</property>
	</bean>

4. null值

假如说一个人没有狗。
属性dog内部直接是null。
(注意空指针异常)

    <bean id="people4" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
		<property name="dog">
			<null></null>
		</property>
	</bean>

5. 级联属性

dog.name是直接级联到了dog对象的name属性,而不像我们之前需要注入一个dog的bean。
需要注意我们在people类中必须要自己new一个dog实例,不然没有dog,显然直接去设置dog.name会有空指针异常,因为实际上相当于需要调用dog的set方法。

    <bean id="people5" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
		<property name="dog.name" value="Jack2"></property>
	</bean>

6. 集合类型属性

我们注入的属性是集合类型,比如list、set、map、properties。
在配置文件中看起来还是比较清晰的。

    <bean id="people6" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="蔡徐坤"></property>
		<property name="age" value="11"></property>
		<property name="dog" ref="dog1"></property>
		<property name="hobbies">
			<list>
				<value>唱歌</value>
				<value>跳舞</value>
			</list>
		</property>
		<property name="loves">
			<set>
				<value>Rap</value>
				<value>打篮球</value>
			</set>
		</property>
		<property name="works">
			<map>
				<entry>
					<key><value>上午</value></key>
					<value>写代码</value>
				</entry>
				<entry>
					<key><value>下午</value></key>
					<value>测试代码</value>
				</entry>
			</map>
		</property>
		<property name="addresses">
			<props>
				<prop key="address1">aaaaa</prop>
				<prop key="address2">bbbbb</prop>
			</props>
		</property>
	</bean>

最后是测试代码,OK。

public class T {
	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	// 基本类型值
	@Test
	public void test1() {
		People people=(People)ac.getBean("people1");
		System.out.println(people);
	}
	
	// 注入bean
	@Test
	public void test2() {
		People people=(People)ac.getBean("people2");
		System.out.println(people);
	}
	
	// 内部bean
	@Test
	public void test3() {
		People people=(People)ac.getBean("people3");
		System.out.println(people);
	}
	
	// 注入null
	@Test
	public void test4() {
		People people=(People)ac.getBean("people4");
		System.out.println(people);
	}
	
	// 级联属性
	@Test
	public void test5() {
		People people=(People)ac.getBean("people5");
		System.out.println(people);
	}
	
	// 注入集合
	@Test
	public void test6() {
		People people=(People)ac.getBean("people6");
		System.out.println(people);
	}
}

装配一个bean和依赖注入

#装配一个bean和依赖注入

一个People类

public class People {
    private int id;
	private String name;
	private int age;

	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 int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

配置文件,id是bean的唯一标识,通过这个id我们可以得到这个实例,这里我们仅仅是用了最普通的一个bean。

<?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="people" class="com.java1234.entity.People"></bean>

</beans>

现在我们要通过注入来设置这些属性。新实例化一个people叫张三,给他注入这些属性。

1. 属性注入

<?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="people" class="com.java1234.entity.People"></bean>
	
	<bean id="people2" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
	</bean>
	
</beans>

我们再重写一下toString()方便查看这些属性。

public class People {
    private int id;
    private String name;
    private int age;

    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 int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
    	return "People [id=" + id + ", name=" + name + ", age=" + age + "]";
    }
}

测试一下

public class Test {
    public static void main(String[] args) {
	    ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
	    People people=(People)ac.getBean("people");
	    System.out.println(people);
	    
	    // 属性注入
	    People people2=(People)ac.getBean("people2");
	    System.out.println(people2);
    }
}

看到如下,成功属性注入
People [id=0, name=null, age=0]
People [id=1, name=张三, age=11]

2. 通过构造函数注入

2.1 通过类型注入

2.2 通过索引注入

2.3 联合使用

给people类再添加一下构造方法

public class People {
	private int id;
	private String name;
	private int age;
	
	public People() {
		super();
	}
	public People(int id, String name, int age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}

	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 int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "People [id=" + id + ", name=" + name + ", age=" + age + "]";
	}
}

配置文件也对应增加这三种方式

//通过类型
<bean id="people4" class="com.java1234.entity.People">
	<constructor-arg index="0" value="3"></constructor-arg>
	<constructor-arg index="1" value="王五"></constructor-arg>
	<constructor-arg index="2" value="55"></constructor-arg>
</bean>

//通过索引
<bean id="people5" class="com.java1234.entity.People">
	<constructor-arg index="0" type="int" value="4"></constructor-arg>
	<constructor-arg index="1" type="String" value="赵六"></constructor-arg>
	<constructor-arg index="2" type="int" value="66"></constructor-arg>
</bean>

//联合使用
<bean id="people5" class="com.java1234.entity.People">
		<constructor-arg index="0" type="int" value="4"></constructor-arg>
		<constructor-arg index="1" type="String" value="赵六"></constructor-arg>
		<constructor-arg index="2" type="int" value="66"></constructor-arg>
</bean>

都是OK滴。

3. 工厂方法注入

我们这里可以理解为我们有个造人工厂(不要想歪)。工厂造人然后帮我们注入属性。

3.1 非静态工厂

这是一个非静态工厂类

package com.java1234.factory;
import com.java1234.entity.People;

public class PeopleFactory {
	public People createPeople(){
		People p=new People();
		p.setId(5);
		p.setName("小七");
		p.setAge(77);
		return p;
	}
}

配置文件指定了一个工厂和工厂里的一个方法去创造我们的people对象。
因为我们这里的工厂是非静态的,所以也要用bean来创造。

	<bean id="peopleFactory" class="com.java1234.factory.PeopleFactory"></bean>
	
	<bean id="people7" factory-bean="peopleFactory" factory-method="createPeople"></bean>

3.2 静态工厂

package com.java1234.factory;
import com.java1234.entity.People;

public class PeopleFactory2 {
	public static People createPeople(){
		People p=new People();
		p.setId(8);
		p.setName("小八");
		p.setAge(88);
		return p;
	}
}

因为这里是静态工厂。我们不需要去new一个实例,直接用 类名.方法() 就可以调用

<bean id="people8" class="com.java1234.factory.PeopleFactory2" factory-method="createPeople"></bean>

Spring对JDBC的支持

Spring对JDBC的支持


Spring中有jdbcTemplate支持,可以连接数据库。
官方文档:https://docs.spring.io/spring/docs/4.3.12.RELEASE/spring-framework-reference/htmlsingle/#jdbc-JdbcTemplate
src中需要一个属性配置文件jdbc.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_spring
jdbc.username=root
jdbc.password=123456

配置文件中

<!--详细内容看官方文档-->
    <!--配置数据源-->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
    <!--加载指定路径的property文件-->
	<context:property-placeholder location="jdbc.properties"/>
    
    <!--定义jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    	<!--注入数据源属性-->
    	<property name="dataSource" ref="dataSource"></property>
    </bean>
public class StudentDaoImpl implements StudentDao{
	private JdbcTemplate jdbcTemplate;
	
	//通过set方法把jdbcTemplate从配置文件里面注入进去
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	@Override
	public int addStudent(Student student) {
		//sql当然还是照写
		String sql="insert into t_student values(null,?,?)";
		//对象数组
		Object []params=new Object[]{student.getName(),student.getAge()};
		//调用jdbc
		return jdbcTemplate.update(sql,params);
	}

	@Override
	public int updateStudent(Student student) {
		String sql="update t_student set name=?,age=? where id=?";
		Object []params=new Object[]{student.getName(),student.getAge(),student.getId()};
		return jdbcTemplate.update(sql,params);
	}

	@Override
	public int deleteStudent(int id) {
		String sql="delete from t_student where id=?";
		Object []params=new Object[]{id};
		return jdbcTemplate.update(sql,params);
	}

	@Override
	public List<Student> findStudents() {
		String sql="select * from t_student";
		final List<Student> studentList=new ArrayList<Student>();
		jdbcTemplate.query(sql, new RowCallbackHandler(){

			@Override
			public void processRow(ResultSet rs) throws SQLException {
				Student student=new Student();
				student.setId(rs.getInt("id"));
				student.setName(rs.getString("name"));
				student.setAge(rs.getInt("age"));
				studentList.add(student);
			}
			
		});
		return studentList;
	}

}

bean之间的关系、bean的作用范围

bean之间的关系、bean的作用范围


bean之间的关系

1.继承

假如我们有几个bean有几个通用的属性,那么我们可以抽象出一个父类。
依然还是People class

public class People {
	private int id;
	private String name;
	private int age;
	private String className;
	private Dog dog;
	
	public People() {
		System.out.println("初始化People");
	}
	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 int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	public Dog getDog() {
		return dog;
	}
	public void setDog(Dog dog) {
		this.dog = dog;
	}
	
	@Override
	public String toString() {
		return "People [id=" + id + ", name=" + name + ", age=" + age
				+ ", className=" + className + ", dog=" + dog + "]";
	}
}

下面看到继承的属性也是可以修改的。李四的年龄为20。

    <bean id="abstractPeople" class="com.java1234.entity.People" abstract="true">
		<property name="className" value="高三5班"></property>
		<property name="age" value="19"></property>
	</bean>
	
	<bean id="zhangsan" parent="abstractPeople">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
	</bean>
	
	<bean id="lisi" parent="abstractPeople">
		<property name="id" value="2"></property>
		<property name="name" value="李四"></property>
		<property name="age" value="20"></property>
	</bean>

2.依赖

我们下面添加依赖关系,用depends-on关键字。也新建Authority类。这样就会先去初始化id为authority的bean

    <bean id="abstractPeople" class="com.java1234.entity.People" abstract="true">
		<property name="className" value="高三5班"></property>
		<property name="age" value="19"></property>
	</bean>
	
	<bean id="zhangsan" parent="abstractPeople" depends-on="autority">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
	</bean>
	
	<bean id="autority" class="com.java1234.service.Authority"></bean>
public class Authority {
	public Authority() {
		System.out.println("获取权限");
	}
}

3.引用

Dog类没有特殊的地方

public class Dog {
	private String name;

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

我们给李四引用一条狗。

    <bean id="dog" class="com.java1234.entity.Dog">
		<property name="name" value="jack"></property>
	</bean>
	
	<bean id="lisi" parent="abstractPeople">
		<property name="id" value="2"></property>
		<property name="name" value="李四"></property>
		<property name="age" value="20"></property>
		<property name="dog" ref="dog"></property>
	</bean>

bean的作用范围

前两个比较重要

  1. singleton Spring ioc 容器中仅有一个Bean 实例,Bean 以单例的方式存在;
  2. prototype 每次从容器中调用Bean 时,都返回一个新的实例;
  3. request 每次HTTP 请求都会创建一个新的Bean;
  4. session 同一个HTTP Session 共享一个Bean;
  5. global session 同一个全局Session 共享一个Bean,一般用于Portlet 应用环境;
  6. application 同一个Application 共享一个Bean;

默认情况下是singleton

    <bean id="dog" class="com.java1234.entity.Dog" scope="singleton">
		<property name="name" value="jack"></property>
	</bean>

下面是测试代码,输出结果为true,因为ioc容器中只有一个bean实例存在。

public class T {
	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	@Test
	public void test1() {
		Dog dog=(Dog)ac.getBean("dog");
		Dog dog2=(Dog)ac.getBean("dog");
		System.out.println(dog==dog2);
	}
}

我们修改scope,这时候再运行相同的测试代码,输出变成了false。

    <bean id="dog" class="com.java1234.entity.Dog" scope="prototype">
		<property name="name" value="jack"></property>
	</bean>

Spring自动装配、方法注入、方法替换

Spring自动装配、方法注入、方法替换


1. 自动装配

之前的bean我们都是手动配置,spring提供自动装配的方法
通过配置default-autowire 属性,Spring IOC 容器可以自动为程序注入bean;默认是no,不启用自动装配;
default-autowire 的类型有byName,byType,constructor;
byName:通过名称进行自动匹配;
byType:根据类型进行自动匹配;
constructor:和byType 类似,只不过它是根据构造方法注入而言的,根据类型,自动注入;
建议:自动装配机制慎用,它屏蔽了装配细节,容易产生潜在的错误;

1.1 byName

还是一人一狗

public class Dog {
	private String name;

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
public class People {
	private int id;
	private String name;
	private int age;
	private Dog dog;

	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 int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Dog getDog() {
		return dog;
	}
	public void setDog(Dog dog) {
		this.dog = dog;
	}
	@Override
	public String toString() {
		return "People [id=" + id + ", name=" + name + ", age=" + age
				+ ", dog=" + dog.getName() + "]";
	}
}

设置 default-autowire="byName" ,即使我们没有把dog的bean手动装配到peolple1中,输出测试依然能输出dog,是Jack,因为根据这里的id="dog",已经自动装配完成了。

<?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"
        default-autowire="byName">

	<bean id="dog1" class="com.java1234.entity.Dog">
		<property name="name" value="Tom"></property>
	</bean>
	
	<bean id="dog" class="com.java1234.entity.Dog">
		<property name="name" value="Jack"></property>
	</bean>
	
	<bean id="people1" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
	</bean>
	
</beans>

1.2 byType

假如我们把上面代码中改成default-autowire="byType",直接运行会报错,因为有两条dog都是Dog类型,按类型匹配不能确定。假如再删掉一个,那就也可以自动配置成功了。

1.3 constructor

给People类加上构造方法

	public People() {
		super();
	}
	public People(Dog dog) {
		super();
		System.out.println("constructor");
		this.dog = dog;
	}

配置文件中改成

<?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"
        default-autowire="constructor">

这里也是根据类型匹配的。所以id不重要。
测试依然能输出dog,是Jack。

2. 方法注入

我们现在还是这样基础的配置文件。

<?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="dog" class="com.java1234.entity.Dog">
		<property name="name" value="Jack"></property>
	</bean>
	
	<bean id="people1" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
	</bean>
	
</beans>

运行以下测试,输出是true,因为获取的dog都是一样的,Spring bean 作用域默认是单例singleton。

public class T {
	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	@Test
	public void test1() {
		System.out.println(ac.getBean("dog")==ac.getBean("dog"));
	}
}

可以通过配置prototype ,实现多例。修改如下。

    <bean id="dog" class="com.java1234.entity.Dog" scope="prototype">
		<property name="name" value="Jack"></property>
	</bean>

这样运行同样测试的输出就是false,因为每一次都获取一个新狗。
接下来我们手动配置一下。如下修改。

    <bean id="people1" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
		<property name="dog" ref="dog"></property>
	</bean>

运行以下测试

    public void test1() {
		People people=(People)ac.getBean("people1");
		People people2=(People)ac.getBean("people1");
		System.out.println(people.getDog()==people2.getDog());
	}

输出是true,这是spring底层注入时已经固定,不能动态改变里面的对象,我暂时这样理解。


所以我们可以用注入方法。
修改People为抽象类,setDog()为抽象方法。

public abstract class People {

	private int id;
	private String name;
	private int age;
	private Dog dog;
	
	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 int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public abstract Dog getDog();
	
	public void setDog(Dog dog) {
		this.dog = dog;
	}
	@Override
	public String toString() {
		return "People [id=" + id + ", name=" + name + ", age=" + age
				+ ", dog=" + dog.getName() + "]";
	}
}

修改配置文件实现getDog()方法动态的注入。注意还是 scope="prototype" 。

    <bean id="people1" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
		<lookup-method name="getDog" bean="dog"/>
	</bean>

这样子spring每次都会帮我们获取一条新的狗。

3. 方法替换

我们现在有People1和People2两个类,他们的getDog方法分别是

    public Dog getDog() {
		Dog dog=new Dog();
		dog.setName("Jack");
		return dog;
	}

    public Dog getDog() {
		Dog dog=new Dog();
		dog.setName("Tom");
		return dog;
	}

我们想让People1拥有People2的方法,也就是得到狗Tom。
我们要让People2实现MethodReplacer接口,删去其他不需要的属性。

public class People2 implements MethodReplacer {

	@Override
	public Object reimplement(Object arg0, Method arg1, Object[] arg2)
			throws Throwable {
		Dog dog=new Dog();
		dog.setName("Tom");
		return dog;
	}
}

配置文件如下

<?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="people1" class="com.java1234.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
		<property name="age" value="11"></property>
		<replaced-method name="getDog" replacer="people2"></replaced-method>
	</bean>
	
	<bean id="people2" class="com.java1234.entity.People2"></bean>
</beans>

我们的测试输出是Tom,替代了原来的Jack。

public class T {
	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	@Test
	public void test1() {
		People people=(People)ac.getBean("people1");
		System.out.println(people.getDog().getName());
	}
}

AOP简介&AOP实例

AOP简介&AOP实例


简介

AOP 简介:百度百科;
面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是Spring
框架中的一个重要内容。利用AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度
降低,提高程序的可重用性,同时提高了开发的效率。
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。

我们模仿一段正常的业务逻辑代码。
先定义接口。

public interface StudentService {
	public void addStudent(String name);
}

下面实现接口。

public class StudentServiceImpl implements StudentService{
	@Override
	public void addStudent(String name) {
		System.out.println("添加学生"+name);
	}
}

配置文件

<bean id="studentService" class="com.java1234.service.impl.StudentServiceImpl"></bean>

测试代码如下,成功输出。

public class T {
	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	@Test
	public void test1() {
		StudentService studentService=(StudentService)ac.getBean("studentService");
		studentService.addStudent("张三");
	}
}

假如现在我们有个需求是要添加日志记录。假如我们修改成如下,有几点缺点。
是对业务代码逻辑的侵入;增加了耦合度;难维护;

public class StudentServiceImpl implements StudentService{
	@Override
	public void addStudent(String name) {
		System.out.println("开始添加学生"+name);
		System.out.println("添加学生"+name);
		System.out.println("完成学生"+name+"的添加");
	}
}

我们应该在addStudent之前和之后进行切入,后面再说。

实例

  1. 前置通知
  2. 后置通知
  3. 环绕通知
  4. 返回通知
  5. 异常通知

我们写一个StudentServiceAspect类。JoinPoint里面有很多方法。

package com.java1234.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class StudentServiceAspect {
	public void doBefore(JoinPoint jp){
		System.out.println("类名:"+jp.getTarget().getClass().getName());
		System.out.println("方法名:"+jp.getSignature().getName());
		System.out.println("开始添加学生:"+jp.getArgs()[0]);
	}
	
	public void doAfter(JoinPoint jp){
		System.out.println("类名:"+jp.getTarget().getClass().getName());
		System.out.println("方法名:"+jp.getSignature().getName());
		System.out.println("学生添加完成:"+jp.getArgs()[0]);
	}
	
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("添加学生前");
		Object retVal=pjp.proceed();
		System.out.println(retVal);
		System.out.println("添加学生后");
		return retVal;
	}
	
	public void doAfterReturning(JoinPoint jp){
		System.out.println("返回通知");
	}
	
	public void doAfterThrowing(JoinPoint jp,Throwable ex){
		System.out.println("异常通知");
		System.out.println("异常信息:"+ex.getMessage());
	}
}

我们修改配置文件,一开始的引入和之前不同,要看文档,还有jar包的配置。

<?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 id="studentServiceAspect" class="com.java1234.advice.StudentServiceAspect"></bean>
	
	<bean id="studentService" class="com.java1234.service.impl.StudentServiceImpl"></bean>
	
	<aop:config>
		<aop:aspect id="studentServiceAspect" ref="studentServiceAspect">
			//定义一个切点,*表示任意,(..)表示参数任意的方法,这样spring能匹配到
			<aop:pointcut expression="execution(* com.java1234.service.*.*(..))" id="businessService"/>
			//调用切面类的doBefore方法
			<aop:before method="doBefore" pointcut-ref="businessService"/>
			//后置通知顾名思义,也类似
			<aop:after method="doAfter" pointcut-ref="businessService"/>
		    //环绕通知
			<aop:around method="doAround" pointcut-ref="businessService"/>
			//返回通知
			<aop:after-returning method="doAfterReturning" pointcut-ref="businessService"/>
			//异常通知
			<aop:after-throwing method="doAfterThrowing" pointcut-ref="businessService" throwing="ex"/>
		</aop:aspect> 
	</aop:config>
</beans>

spring ioc理解

Spring IOC的理解

IOC(控制反转:Inverse Of Control),又叫依赖注入,是OOP中一种解决耦合问题的方法,也是Spring框架的核心。

这是一个 张三 类,一个方法是测试。

public class ZhangSan {
    public void test(){
	    System.out.println("张三-测试程序");
    }
}

public class JavaWork {
    public void doTest(){
	    Zhangsan zhangsan = new Zhangsan();
	    zhangsan.test();
    }
}

public class BossTest {
    public static void main(String[] args) {
	    JavaWork javaWork=new JavaWork();
	    javaWork.doTest();
    }
}

这个时候就是耦合的,因为Javawork类依赖Zhangsan类,Test类依赖JavaWork类,假如我不要张三测试要李四测试,代码的改动太大很麻烦。因此所以我们把控制谁去做测试的权力转交出来给BossTest。
我们去实现一个接口,然后让张三和李四继承这个接口。

public interface Tester {
    public void test();
}

public class ZhangSan implements Tester{
    public void test(){
	    System.out.println("张三-测试程序");
    }
}

public class Lisi implements Tester{
    public void test(){
	    System.out.println("李四-测试程序");
    }
}

我们再给JavaWork定义一个tester属性,决定谁去测试。

public class JavaWork {
    private Tester tester;
    
    public void setTester(Tester tester) {
	    this.tester = tester;
    }
    
    public void doTest(){
	    tester.test();
    }
}

在BossTest中决定这个人是谁。

public class BossTest {
    public static void main(String[] args) {
	    JavaWork javaWork=new JavaWork();
	    javaWork.setTester(new ZhangSan());
	    javaWork.doTest();
    }
}

现在控制权已经转交给了BossTest,控制权已经翻转。我们换成李四也很简单。
这里依然还是需要一个main方法来指定。
我们引入spring之后用spring管理IOC容器。

<?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="zhangsan" class="com.java1234.service.ZhangSan"></bean>

    <bean id="lisi" class="com.java1234.service.Lisi"></bean>

    <bean id="javaWork" class="com.java1234.service.JavaWork">
	    <property name="tester" ref="lisi"></property>
    </bean>
    
</beans>

bean对应了张三和李四,另一个bean对应JavaWork,它的tester属性我们也可以通过spring设置,具体值我们用ref应用,它会自动调用JavaWork的set方法,把张三的实例对象设置进去。

public class BossTest2 {
    public static void main(String[] args) {
        //获取bean
	    ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
	    //设置bean
	    JavaWork javaWork=(JavaWork)ac.getBean("javaWork");
	    javaWork.doTest();
    }
}

如果这个时候我们再要去换成李四,我们只要改xml配置文件就可以,不需要改任何代码。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.