如果您想了解详解Java的Spring框架中bean的注入集合的相关知识,那么本文是一篇不可错过的文章,我们将对spring框架注入bean工作原理进行全面详尽的解释,并且为您提供关于JavaSpri
如果您想了解详解Java的Spring框架中bean的注入集合的相关知识,那么本文是一篇不可错过的文章,我们将对spring框架注入bean工作原理进行全面详尽的解释,并且为您提供关于Java Spring框架创建项目与Bean的存储与读取详解、JavaWeb_(Spring框架)在Struts+Hibernate框架中引入Spring框架、Java的Spring框架中AOP项目的一般配置和部署教程、Java的Spring框架中bean的继承与内部bean的注入的有价值的信息。
本文目录一览:- 详解Java的Spring框架中bean的注入集合(spring框架注入bean工作原理)
- Java Spring框架创建项目与Bean的存储与读取详解
- JavaWeb_(Spring框架)在Struts+Hibernate框架中引入Spring框架
- Java的Spring框架中AOP项目的一般配置和部署教程
- Java的Spring框架中bean的继承与内部bean的注入
详解Java的Spring框架中bean的注入集合(spring框架注入bean工作原理)
这篇文章主要介绍了详解Java的Spring框架中bean的注入集合,Spring是Java的SSH三大web开发框架之一,需要的朋友可以参考下
使用value属性和使用标签的ref属性在你的bean配置文件中的对象引用,这两种情况下可以处理单值到一个bean,如果你想通过多元值,如Java Collection类型List, Set, Map 及 Properties。要处理这种情况,Spring提供了四种类型的如下集合的配置元素:
可以使用 或 来连接任何实现java.util.Collection或数组。
会遇到两种情况(a)将收集的直接的值及(b)传递一个bean的引用作为集合的元素之一。
例子:
我们使用Eclipse IDE,然后按照下面的步骤来创建一个Spring应用程序:
这里是JavaCollection.java文件的内容:
package com.yiibai; import java.util.*; public class JavaCollection { List addressList; Set addressSet; Map addressMap; Properties addressprop; // a setter method to set List public void setAddressList(List addressList) { this.addressList = addressList; } // prints and returns all the elements of the list. public List getAddressList() { System.out.println("List Elements :" + addressList); return addressList; } // a setter method to set Set public void setAddressSet(Set addressSet) { this.addressSet = addressSet; } // prints and returns all the elements of the Set. public Set getAddressSet() { System.out.println("Set Elements :" + addressSet); return addressSet; } // a setter method to set Map public void setAddressMap(Map addressMap) { this.addressMap = addressMap; } // prints and returns all the elements of the Map. public Map getAddressMap() { System.out.println("Map Elements :" + addressMap); return addressMap; } // a setter method to set Property public void setAddressprop(Properties addressprop) { this.addressprop = addressprop; } // prints and returns all the elements of the Property. public Properties getAddressprop() { System.out.println("Property Elements :" + addressprop); return addressprop; } }
以下是MainApp.java文件的内容:
package com.yiibai; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClasspathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClasspathXmlApplicationContext("Beans.xml"); JavaCollection jc=(JavaCollection)context.getBean("javaCollection"); jc.getAddressList(); jc.getAddressSet(); jc.getAddressMap(); jc.getAddressprop(); } }
以下是配置文件beans.xml文件里面有配置的集合的所有类型:
INDIAPakistanUSAUSAINDIAPakistanUSAUSAINDIAPakistanUSAUSA
创建源代码和bean配置文件完成后,让我们运行应用程序。如果应用程序一切顺利,这将打印以下信息:
List Elements :[INDIA, Pakistan, USA, USA] Set Elements :[INDIA, Pakistan, USA] Map Elements :{1=INDIA, 2=Pakistan, 3=USA, 4=USA} Property Elements :{two=Pakistan, one=INDIA, three=USA, four=USA}
注入Bean引用:
下面bean定义将帮助您了解如何注入bean的引用作为集合的元素之一。甚至可以混合引用和值都在一起,如下图所示:
PakistanPakistan
使用上面的bean定义,需要定义这样一种方式,他们应该能够处理的参考,以及setter方法。
注入null和空字符串的值
如果需要传递一个空字符串作为值,如下所示:
前面的例子等同于Java代码: exampleBean.setEmail("")
如果需要传递一个null值,如下所示:
前面的例子等同于Java代码:exampleBean.setEmail(null)
Java Spring框架创建项目与Bean的存储与读取详解
本文思维导图:
1.Spring项目的创建
1.1创建Maven项目
第一步,创建Maven项目,Spring也是基于Maven的。
1.2添加spring依赖
第二步,在Maven项目中添加Spring的支持(spring-context, spring-beans)
在pom.xml
文件添加依赖项。
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.2.3.RELEASE</version> </dependency> </dependencies>
刷新等待加载完成。
1.3创建启动类
第三步,创建启动类与main,用来做简单的测试
在java目录创建类,写代码即可,因为这里只演示怎么创建Spring项目和介绍Spring的简单使用,就不依赖那些Tomcat什么的了,直接写一个Main类更直观。
1.4配置国内源
由于国外源不稳定,可能第二步引入spring依赖会失败,所以下面介绍如何配置国内镜像源。
现成的settings.xml文件链接:
地址1
地址2:提取码: 9thv
如果你已经有了settings文件,但没有配置mirror
,配置内容如下:
<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>
2.储存或读取Bean对象
2.1添加spring配置文件
添加spring配置文件(首次才需要,非首次可忽略此步骤)
右键resources目录,新建一个.xml
配置文件,文件名推荐spring.xml
或者spring-config.xml
。
创建一个spring.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"> </beans>
2.2创建Bean对象
第一步,创建Bean
对象。
比如我们要注入一个User
对象,就先的创建一个User
类。
package com.bean; public class User { public void sayHi(String name) { System.out.println("你好!" + name); } }
将Bean
通过配置文件,注入到spring中,即在spring配置文件中通过以下语句注入。
<bean id="user"></bean>
spring中对象的储存是通过键值对来存储的,其中key
为id
,value
为class
。
命名规范:id
使用小驼峰命名,如userid
,class
使用大驼峰命名,如userId
。
2.3读取Bean对象
想要从spring中将Bean
对象读取出来,先要得到spring上下文对象,相当于得到了spring。再通过spring上下文对象提供的方法获取需要使用的Bean
对象。最后就能使用Bean
对象了。
import com.bean.User; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { //1.得到上下文对象 ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); //2.获取bean对象,此处是根据id获取 User user = (User) context.getBean("user"); //3.使用bean user.sayHi("zhangsan"); } }
运行结果:
你好!zhangsan
Process finished with exit code 0
还可以使用Bean工厂(旧)来获取Bean。
import com.bean.User; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; public class Main2 { public static void main(String[] args) { //1.得到Bean工厂 BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring.xml")); //2.获取Bean User user = (User) factory.getBean("user"); //3.使用 user.sayHi("李四"); } }
虽然Bean工厂XmlBeanFactory类现在已经废弃了,但是目还能使用的,当然创建Bean工厂有新的方式,但老的方式比较直观,因此演示采用老的方式创建。
运行结果:
你好!李四
Process finished with exit code 0
发现ApplicationContext
与BeanFactory
都可以从容器中获取Bean
,都提供了getBean
方法,那问题来了,ApplicationContext
与BeanFactory
有什么区别?
相同点:都可以从容器中获取Bean
,都提供了getBean
方法。
不同点:
BeanFactory
是ApplicationContext
的父类,BeanFactory
只提供了基础访问Bean
对象的功能,而ApplicationContext
除了拥有BeanFactory
的全部功能,还有其他额外功能的实现,如国际化,资源访问等功能实现。- 从性能方面来说是不同的,
BeanFactory
按需加载Bean
,属于懒汉方式,ApplicationContext
是饿汉方式,在创建时会将所有的Bean
都加载,以备使用。
证明:
我们在bean目录下添加一个Blog
类,并完善Blog
与User
类的构造方法,当类被构造时会发出一些信号,在获取上下文或工厂时根据这些信号让我们感知到它是否会被构造。
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main3 { public static void main(String[] args) { //1.得到上下文对象 ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); } }
运行结果:
ApplicationContext创建时,会将所有的对象都构造,饿汉的方式。
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; public class Main4 { public static void main(String[] args) { //1.得到Bean工厂 BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring.xml")); } }
BeanFactory创建时,什么都没有,说明是懒汉的方式。
ApplicationContext
中的多种getBean
方法:
方法1:根据 bean name
获取bean
。
User user = (User) context.getBean("user");
方法2:根据bean type
获取bean
。
User user = (User) context.getBean(User.class);
只有beans中只有一个类的实例没有问题,但是个有多个同类的实例,会有问题,即在spring中注入多个同一个类的对象,就会报错。
我们来试一试,首先在Spring配置文件,注入多个User
对象:
然后我们再通过这种方式来获取对象,我们发现报错了,报错信息如下:
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ''com.bean.User'' available: expected single matching bean but found 3: user,user1,user2
抛出了一个NoUniqueBeanDefinitionException
异常,表示注入的对象不是唯一的。
方法3:综合上述两种,可以根据bean name
与bean type
来获取bean
相比方法1,更加健壮。
User user = context.getBean("user", User.class);
小结:
到此这篇关于Java Spring框架创建项目与Bean的存储与读取详解的文章就介绍到这了,更多相关Java Spring框架内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
- Spring五大类注解读取存储Bean对象的方法
- Spring存储与读取Bean对象方法
JavaWeb_(Spring框架)在Struts+Hibernate框架中引入Spring框架
spring的功能:简单来说就是帮我们new对象,什么时候new对象好,什么时候销毁对象。
在MySQL中添加spring数据库,添加user表,并添加一条用户数据
使用struts + hibernate框架实现用户登陆功能:当用户在login.jsp中账号密码输入错误,重定向login.jsp,并提示用户输入账号、密码错误,如果用户在login.jsp中账号密码输入正确,跳转到index.html


<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/head.css" />
<link rel="stylesheet" type="text/css" href="css/login.css" />
</head>
<body>
<div class="dvhead">
<div class="dvlogo">
<a href="index.html">你问我答</a>
</div>
<div class="dvsearch">10秒钟注册账号,找到你的同学</div>
<div class="dvreg">
已有账号,立即 <a href="login.html">登录</a>
</div>
</div>
<section class="sec">
<form action="${pageContext.request.contextPath }/UserAction_login" method="post">
<div class="register-box">
<label for="username" class="username_label"> 用 户 名 <input
maxlength="20" name="username" type="text" placeholder="您的用户名和登录名" />
</label>
<div class="tips"></div>
</div>
<div class="register-box">
<label for="username" class="other_label"> 密 码 <input
maxlength="20" type="password" name="password"
placeholder="建议至少使用两种字符组合" />
</label>
<div class="tips"></div>
</div>
<div class="arguement">
<input type="checkbox" id="xieyi" /> 阅读并同意 <a
href="javascript:void(0)">《你问我答用户注册协议》</a> <a href="register.html">没有账号,立即注册</a>
<div class="tips" style="color: red" > <s:property value="#error"/> </div>
</div>
<div class="submit_btn">
<button type="submit" id="submit_btn">立 即 登录</button>
</div>
</form>
</section>
<script src="js/index.js" type="text/javascript" charset="utf-8"></script>
</body>


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.devMode" value="true"></constant>
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<package name="spring" namespace="/" extends="struts-default">
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="UserAction_*" class="com.Gary.web.UserAction" method="{1}">
<result name="login">/login.jsp</result>
<result name="toIndex" type="redirect">/index.html</result>
</action>
</package>
</struts>


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///spring</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connecton.password">123456</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 隔离级别 不可重复读 -->
<property name="hibernate.connection.isolation">4</property>
<property name="hibernate.current_session_context_class">thread</property>
<mapping resource="com/Gary/domain/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>


package com.Gary.web;
import com.Gary.domain.User;
import com.Gary.service.UserService;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class UserAction extends ActionSupport implements ModelDriven<User>{
public User user = new User();
public String login() throws Exception {
UserService userService = new UserService();
boolean success = userService.findUser(user);
if(success)
{
return "toIndex";
}else {
ActionContext.getContext().put("error", "用户名或者密码错误!!");
return "login";
}
}
@Override
public User getModel() {
return user;
}
}


package com.Gary.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static SessionFactory sessionFactory = null;
static {
Configuration config = new Configuration().configure();
sessionFactory = config.buildSessionFactory();
}
public static Session getSession()
{
return sessionFactory.openSession();
}
public static Session getCurrentSession()
{
return sessionFactory.getCurrentSession();
}
}


package com.Gary.service;
import org.hibernate.Transaction;
import com.Gary.dao.UserDao;
import com.Gary.domain.User;
import com.Gary.utils.HibernateUtils;
public class UserService {
public boolean findUser(User user) {
UserDao userDao = new UserDao();
Transaction beginTransaction = HibernateUtils.getCurrentSession().beginTransaction();
User temp = null;
try {
temp = userDao.findUser(user);
}catch(Exception e){
beginTransaction.rollback();
}
beginTransaction.commit();
return temp==null?false:true;
}
}


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.Gary.domain">
<class name="User" table="user">
<id name="id">
<generator class="uuid"></generator>
</id>
<property name="username" column="username"></property>
<property name="password" column="password"></property>
</class>
</hibernate-mapping>


package com.Gary.domain;
public class User {
private String id;
private String username;
private String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}


package com.Gary.dao;
import org.hibernate.Session;
import org.hibernate.query.NativeQuery;
import com.Gary.domain.User;
import com.Gary.utils.HibernateUtils;
public class UserDao {
public User findUser(User user) {
Session session = HibernateUtils.getCurrentSession();
//sql操作数据库
String sql = "select * from user where username = ? and password = ?";
NativeQuery sqlQuery = session.createSQLQuery(sql);
sqlQuery.addEntity(User.class);
sqlQuery.setParameter(1, user.getUsername());
sqlQuery.setParameter(2, user.getPassword());
User result = (User) sqlQuery.uniqueResult();
return result;
}
}
Spring介入,启动Spring,在web.xml中进行配置
<!-- 让spring随着web项目的启动而启动 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置spring配置文件的位置 -->
<context-param>
<param-name>contextConfiguration</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>Spring</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- 让spring随着web项目的启动而启动 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置spring配置文件的位置 -->
<context-param>
<param-name>contextConfiguration</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
修改UserService.java和UserDao,不用再UserAction中使用UserService userService = new UserService(),使用Spring框架帮我们new对象


package com.Gary.web;
import com.Gary.domain.User;
import com.Gary.service.UserService;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class UserAction extends ActionSupport implements ModelDriven<User>{
public User user = new User();
private UserService userService;
public String login() throws Exception {
boolean success = userService.findUser(user);
if(success)
{
return "toIndex";
}else {
ActionContext.getContext().put("error", "用户名或者密码错误!!");
return "login";
}
}
@Override
public User getModel() {
return user;
}
public UserService getUserService() {
return userService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}


package com.Gary.service;
import org.hibernate.Transaction;
import com.Gary.dao.UserDao;
import com.Gary.domain.User;
import com.Gary.utils.HibernateUtils;
public class UserService {
private UserDao userDao;
public boolean findUser(User user) {
Transaction beginTransaction = HibernateUtils.getCurrentSession().beginTransaction();
User temp = null;
try {
temp = userDao.findUser(user);
}catch(Exception e){
beginTransaction.rollback();
}
beginTransaction.commit();
return temp==null?false:true;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
applicationContext.xml中进行Action、Service的配置,Dao暂时不配置
<!-- 配置Action -->
<bean name = "userAction" class="com.Gary.web.UserAction" scope="prototype">
<property name="userService" ref="userService"></property>
</bean>
<!-- 配置Service -->
<bean name="userService" class="com.Gary.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 配置Dao -->
<bean name="userDao" class="com.Gary.dao.UserDao">
</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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置Action -->
<bean name = "userAction" class="com.Gary.web.UserAction" scope="prototype">
<property name="userService" ref="userService"></property>
</bean>
<!-- 配置Service -->
<bean name="userService" class="com.Gary.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 配置Dao -->
<bean name="userDao" class="com.Gary.dao.UserDao">
</bean>
</beans>
在struts.xml中告诉struts不用创建Action,sping来帮你创建Action
<!-- 告诉struts,你不用创建Action,sping来帮你创建Action -->
<constant name="struts.objectFactory" value="spring"></constant>


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.devMode" value="true"></constant>
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<!-- 告诉struts,你不用创建Action,sping来帮你创建Action -->
<constant name="struts.objectFactory" value="spring"></constant>
<package name="spring" namespace="/" extends="struts-default">
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="UserAction_*" class="com.Gary.web.UserAction" method="{1}">
<result name="login">/login.jsp</result>
<result name="toIndex" type="redirect">/index.html</result>
</action>
</package>
</struts>
引入Spring框架,添加applicationContext.xml
(引入Spring框架后修改过的一些东西)


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>Spring</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- 让spring随着web项目的启动而启动 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置spring配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>


<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置Action -->
<bean name = "userAction" class="com.Gary.web.UserAction" scope="prototype">
<property name="userService" ref="userService"></property>
</bean>
<!-- 配置Service -->
<bean name="userService" class="com.Gary.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 配置Dao -->
<bean name="userDao" class="com.Gary.dao.UserDao">
</bean>
</beans>


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///spring</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connecton.password">123456</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 隔离级别 不可重复读 -->
<property name="hibernate.connection.isolation">4</property>
<property name="hibernate.current_session_context_class">thread</property>
<mapping resource="com/Gary/domain/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.devMode" value="true"></constant>
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<!-- 告诉struts,你不用创建Action,sping来帮你创建Action -->
<constant name="struts.objectFactory" value="spring"></constant>
<package name="spring" namespace="/" extends="struts-default">
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="UserAction_*" class="com.Gary.web.UserAction" method="{1}">
<result name="login">/login.jsp</result>
<result name="toIndex" type="redirect">/index.html</result>
</action>
</package>
</struts>


package com.Gary.web;
import com.Gary.domain.User;
import com.Gary.service.UserService;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class UserAction extends ActionSupport implements ModelDriven<User>{
public User user = new User();
private UserService userService;
public String login() throws Exception {
boolean success = userService.findUser(user);
if(success)
{
return "toIndex";
}else {
ActionContext.getContext().put("error", "用户名或者密码错误!!");
return "login";
}
}
@Override
public User getModel() {
return user;
}
public UserService getUserService() {
return userService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}


package com.Gary.service;
import org.hibernate.Transaction;
import com.Gary.dao.UserDao;
import com.Gary.domain.User;
import com.Gary.utils.HibernateUtils;
public class UserService {
private UserDao userDao;
public boolean findUser(User user) {
Transaction beginTransaction = HibernateUtils.getCurrentSession().beginTransaction();
User temp = null;
try {
temp = userDao.findUser(user);
}catch(Exception e){
beginTransaction.rollback();
}
beginTransaction.commit();
return temp==null?false:true;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
Java的Spring框架中AOP项目的一般配置和部署教程
这篇文章主要介绍了Java的Spring框架中AOP项目的一般配置和部署教程,AOP面向方面编程的项目部署结构都比较类似,因而也被看作是Spring的一种设计模式使用,需要的朋友可以参考下
0.关于AOP
面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP是OOP的延续。
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。
在Spring中提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的――完成业务逻辑――仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
1.通过PropertyPlaceholderConfigurer在Spring中加载其他外部配置文件或者属性文件:
在很多javaEE工程中,Spring的角色非常重要,是一个管理其他模块和组件的轻量级容器,Spring经常需要管理Struts、Ibatis、Hibernate等,这些开源框架的配置文件就通过Spring的PropertyPlaceholderConfigurer加载在Spring中进行管理,另外,数据库连接信息、JNDI连接信息属性文件等也可以通过PropertyPlaceholderConfigurer加载到Spring中来管理。用法如下:
(1).通过PropertyPlaceholderConfigurer将其他文件加载到Spring中:
在spring配置文件中添加如下配置:
classpath:要加载的文件名 ……
(2).经过(1)中的配置要加载的配置或属性文件就被加载到spring中,如果还需要在运行时使用加载进来的配置或数据文件的一些信息,如使用数据库连接信息或者JNDI连接信息时,就可以使用类型EL表达式的语法进行引用,例如:
注意:也可以使用
2.Java的动态代理:
Spring的面向切面编程(AOP)底层实现原理是动态代理,因此在学习面向切面编程之前必须先了解动态代理。
Java中动态代理应用非常广泛,动态代理是23中设计模式中非常常用的经典设计模式之一。动态代理的原理是,当要调用一个目标对象或者其方法时,系统并不是直接返回目标对象,而是返回一个代理对象,通过这个代理对象去访问目标对象或者目标对象的方法。
动态代理的简单原理如下:
客户端调用者――>代理对象――>被调用的目标对象。
当客户端调用代理对象时,代理对象委派目标对象调用其业务方法。
动态代理分为两种,针对接口的动态代理和针对普通类的动态代理,java中的动态代理是真的接口的动态代理,cglib是针对普通类的动态代理,目标javaEE的依赖包和Spring的jar包中已经包含了cglib相关jar包,因此即可以对代理也可以对普通类进行动态代理。
(1).java的针对接口动态代理:
Java中的动态代理只能针对接口进行动态代理,因此,目标对象必须实现接口,代理对象要实现目标对象的所有接口。工作流程如下:
a.动态代理类编写:
注意:动态代理必须实现InvocationHandler接口,同时实现以下方法:
复制代码 代码如下:
Object invoke(Objectm代理实例,Method代理实例上调用的接口方法的Method 实例,Object[] 传入代理实例上方法调用的参数值的对象数组);
安装JDK的文档说明,该方法作用是传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。b.创建代理对象:
Proxy.newProxyInstance(类加载器, Class>[]接口数组,回调代理对象(一般是this))
当调用目标对象方法时,通过该方法创建目标对象的代理对象,代理对象会自动调用其invoke方法调用目标对象,并将调用结果返回。
(2).cglib针对普通java类动态代理:
cglib创建动态代理时,不要求目标类必须实现接口,其工作流程如下:
a.动态代理类编写:
Enhancer enhancer = new Enhancer(); //设置目标类的父类为其本身 enhancer.setSuperclass(目标类对象.getClass()); //设置回调对象为动态代理对象本身 enhancer.setCallback(this);
b.实现MethodInterceptor接口:
实现以下方法:
Object intercept(Objectm代理实例,Method代理实例上调用的接口方法的Method 实例,Object[] 传入代理实例上方法调用的参数值的对象数组,MethodProxy 方法代理实例);
注意:cglib不但可以针对类动态代理,还可以针对方法动态代理。
3.面向切面编程(AOP)的基础概念:
以一个普通的java方法来举例
public 返回类型 方法名(参数列表){ ――>环绕通知 方法前处理代码 ――> 前置通知 try{ 方法具体实现(方法体)……. 方法后处理代码 ――> 后置通知 }Catch(异常类型 e){ 异常处理…… ――> 例外通知 }finally{ 最后处理代理…… ――> 最终通知 } }
a. 横切关注点:如上面5个通知的位置,在java对象中,可以这些具有类似共同处理逻辑的位置加入如权限验证、事物处理、日志记录等处理逻辑的对象称为横切关注点,面向对象编程(OOP)的关注点是纵向将现实世界的事物抽象成编程的对象模型。而面向切面编程(AOP)的关注点是横向的,它将编程对象模型中拥有类似处理逻辑的地方抽象出来形成切面,而编程对象中的处理逻辑就是横切关注点。
b. 切面(Aspect):将横切关注点抽象就形成切面,与类类似,二者关注点不同,类是事物特性的抽象,切面是横切关注点的抽象。
c. 连接点(Joinpoint):被拦截到的点,在Spring中指方法,因为spring只支持方法类型的连接点,即被拦截的方法。如上面例子的方法。
d. 切入点(pointcut):指对连接点进行拦截的定义,是连接点的集合,即一系列被拦截方法的集合。
e. 通知(Advice):指拦截到连接点之后要做的事情,即拦截之后的逻辑处理。通常的权限验证、事物处理、日志记录等操作就是在通知中定义和完成的。
f. 目标对象(Target):代理的目标对象,即被拦截的对象。如上面例子中方法所在的对象。
g. 织入(weave):指将切面应用到目标对象,并导致代理对象创建的过程。
h. 引入(Introduction):在不修改代码的前提下,引入可以在运行期为类动态的添加一些方法和字段。
4. Spring中支持面向切面编程(AOP)的依赖包:
Spring解压后目录中的如下3个包:
lib/aspectj/aspectjweaver.jar lib/aspectj/aspectjrt.jar lib/cglib/cglib-nodep-2.1-3.jar
5. 在spring中使用面向切面编程(AOP)时,需要在spring配置文件中引入aop的命名空间,即添加如下的配置:
xmlns:aop=”http://www.springframework.org/schema/aop” “http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd”
注意:Spring2.5以后提供两种AOP方法,即基于xml配置文件方式和基于java注解方式。
若要使用注解方式的aop,需要在spring配置文件中添加如下的对象注解方式aop的支持:
6. JavaBean的包装类――BeanWrapper:
Spring通过BeanWrapper类封装一个javabean的行为,可以设置和获取其属性值,如:
BeanWrapper 包装类对象 = BeanWrapperImpl(new 被包装类()); 包装类对象.setPropertyValue(“属性名”,”属性值”);
通过这种方法就可以给被包装类设置属性。
7. 基于注解方式的面向切面编程(AOP)开发:
(1).在spring配置文件中加入对注解方法的aop支持。
(2).定义切面:
和创建普通类类似,在类前加上”@Aspect”注解,表明该类是一个切面。
(3).在切面中加入切入点:
切入点就是被拦截对象方法的集合,通常切入点定义在切面中某个对切入点进行处理的方法上。使用”@pointcut”注解,语法如下:
@pointcut(“execution(* com.test.service..*.*(..))”) public void anyMethod(){//方法名为切入点名 切入点处理 }
语法参数详解:
a. 第一个”*”:表示被拦截的方法是任意的返回类型。
b. com.test.service:这里是举一个简单的例子,表示要被拦截的包名,即被拦截的包。
c.被拦截包名后面的两个”..”:表示被拦截包下面的子包也递归进行拦截,即被拦截的子包。
d. ”..”之后的”*”:表示被拦截包及其子包下面的所有类,即被拦截的类。
e. 最后一个”*”:表示被拦截类中的所有方法,即被拦截的方法。
f. ”(..)”:表示被拦截的方法接收任意的参数,即被拦截的参数。
注意:切入点定义语法可以支持通配符,但是一定要严格遵循语法规则。如:
@pointcut(“execution(*com.test.service..*.add*(..))”)
表示对com.test.service包及其子包下所有的类中以”add”开头的方法进行拦截。
(4).在切面中添加通知:
Spring中通知位置请参看3中的小例子。
”@Before”注解:声明前置通知。
“@AfterRutruning”注解:声明后置通知。
“@After”注解:声明最终通知。
“@AfterThrowing”注解:声明例外通知。
“@Around”注解:声明环绕通知。
一个定义通知的例子如下:
@Before(“anyMethod()(切面中声明的切入点名)”) public void doAccessCheck(){ …… }
注意:环绕通知和其他4种通知的稍有不同,环绕通知的定义方式比较特别,环绕通知在整个方法调用前后都会起作用,因此必须使用连接点对象告诉连接点在环绕通知处理之后继续其逻辑处理。其定义方式如下:
@Around(切入点名) public Object dobasicProfiling(ProcedingJoinPoint pjp) throws Throwable{ …… return pjp.proceed();//该句是告诉连接点继续执行其他的操作 }
8.基于注解方式的面向切面编程(AOP)开发的一些小技巧:
(1).获取输入参数:
如:
@Before(“切入点名 && args(输入参数名)”) public void doSomething(String 输入参数名){……}
(2).获取返回结果:
如:
@AfterReturning(pointcut=”切入点名”,returning=”返回结果名”) public void dosomething(String 结果名){……}
9.基于XML方式的面向切面编程(AOP)开发:
(1).定义切面类,在切面类中添加通知。
(2).将切面类想普通java类一样在spring配置文件中配置。
(3).在spring配置文件中添加AOP配置如下:
……
10. Spring的事务处理(Spring的声明式事务处理):
事务简单来说是指数据库中的一条最基本的操作,关于事务的详细讲解以后会在数据库相关总结中具体说明。Spring的面向切面编程(AOP)一个最重要的应用是事务管理,Spring2.5以后版本的事务管理支持基于注解的方式和基于XML文件的方式两种:
(1).基于注解方式的事务管理:
a. 在spring配置文件中添加事务管理的命名空间如下:
xmlns:ts=http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
b. 在spring配置文件中配置事务管理器如下:
c.在spring配置文件中添加支持注解方式的事务配置项如下:
d.使用基于注解的事务管理:
在Spring所管理的JavaEE工程中,需要使用事务的业务逻辑地方加上“@Transactional”注解。
(2).基于XML文件方式的事务管理:
a. 在spring配置文件中配置事务管理器如下:
b.在spring配置文件中添加事物管理的切面如下:
c.在spring配置文件中为事务通知添加事物处理特性如下:
Java的Spring框架中bean的继承与内部bean的注入
bean的定义继承
bean定义可以包含很多的配置信息,包括构造函数的参数,属性值,比如初始化方法,静态工厂方法名等容器的具体信息。
子Bean定义从父定义继承配置数据。子的定义可以覆盖一些值,或者根据需要添加其他。
Spring bean定义继承无关,与java类的继承,但继承的概念是一样的。你可以定义一个父bean定义为模板和其他孩子Bean可以从父bean继承所需的配置。
当使用基于XML的配置元数据,指明一个子Bean定义使用所在的当前属性指定的父bean作为这个属性的值。
例如:
让我们使用Eclipse IDE,然后按照下面的步骤来创建一个Spring应用程序:
以下是我们定义的“HelloWorld”豆里面有两个属性message1和message2配置文件beans.xml中。下一步“helloIndia”豆已经被定义为“HelloWorld”的子Bean使用parent属性。该子Bean继承message2属性原状,并覆盖message1 属性,并引入多一个属性message3。
<?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-3.0.xsd"> <bean id="helloWorld"> <property name="message1" value="Hello World!"/> <property name="message2" value="Hello Second World!"/> </bean> <bean id="helloIndia"parent="helloWorld"> <property name="message1" value="Hello India!"/> <property name="message3" value="Namaste India!"/> </bean> </beans>
这里是HelloWorld.java 文件的内容:
package com.jb51.cc; public class HelloWorld { private String message1; private String message2; public void setMessage1(String message){ this.message1 = message; } public void setMessage2(String message){ this.message2 = message; } public void getMessage1(){ System.out.println("World Message1 : " + message1); } public void getMessage2(){ System.out.println("World Message2 : " + message2); } }
这里是HelloIndia.java文件的内容:
package com.jb51.cc; public class HelloIndia { private String message1; private String message2; private String message3; public void setMessage1(String message){ this.message1 = message; } public void setMessage2(String message){ this.message2 = message; } public void setMessage3(String message){ this.message3 = message; } public void getMessage1(){ System.out.println("India Message1 : " + message1); } public void getMessage2(){ System.out.println("India Message2 : " + message2); } public void getMessage3(){ System.out.println("India Message3 : " + message3); } }
以下是MainApp.java文件的内容:
package com.jb51.cc; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClasspathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClasspathXmlApplicationContext("Beans.xml"); HelloWorld objA = (HelloWorld) context.getBean("helloWorld"); objA.getMessage1(); objA.getMessage2(); HelloIndia objB = (HelloIndia) context.getBean("helloIndia"); objB.getMessage1(); objB.getMessage2(); objB.getMessage3(); } }
创建完成源代码和bean配置文件,让我们运行应用程序。如果一切顺利,这将打印以下信息:
World Message1 : Hello World! World Message2 : Hello Second World! India Message1 : Hello India! India Message2 : Hello Second World! India Message3 : Namaste India!
如果你在这里看到,我们没有通过message2同时创建“helloIndia”的bean,但它通过了,因为bean定义的继承。
bean定义模板:
您可以创建可以在不会花太多功夫被其他子Bean定义的bean定义模板。在定义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-3.0.xsd"> <bean id="beanTeamplate" abstract="true"> <property name="message1" value="Hello World!"/> <property name="message2" value="Hello Second World!"/> <property name="message3" value="Namaste India!"/> </bean> <bean id="helloIndia"parent="beanTeamplate"> <property name="message1" value="Hello India!"/> <property name="message3" value="Namaste India!"/> </bean> </beans>
父bean不能被实例化它自己,因为它是不完整的,而且它也明确地标记为抽象。当一个定义是抽象的这个样子,它只是作为一个纯粹的模板bean定义,充当子定义的父定义使用。
注入内部bean
正如你所知道的Java内部类是其他类的范围内定义的,同样,内部bean是被其他bean的范围内定义的bean。因此<property/>或<constructor-arg/>元素内<bean/>元件被称为内部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-3.0.xsd"> <bean id="outerBean"> <property name="target"> <bean id="innerBean"/> </property> </bean> </beans>
例如:
我们使用Eclipse IDE,然后创建一个Spring应用程序,
这里是TextEditor.java文件的内容:
package com.jb51.cc; public class TextEditor { private SpellChecker spellChecker; // a setter method to inject the dependency. public void setSpellChecker(SpellChecker spellChecker) { System.out.println("Inside setSpellChecker." ); this.spellChecker = spellChecker; } // a getter method to return spellChecker public SpellChecker getSpellChecker() { return spellChecker; } public void spellCheck() { spellChecker.checkSpelling(); } }
下面是另外一个相关的类文件SpellChecker.java内容:
package com.jb51.cc; public class SpellChecker { public SpellChecker(){ System.out.println("Inside SpellChecker constructor." ); } public void checkSpelling(){ System.out.println("Inside checkSpelling." ); } }
以下是MainApp.java文件的内容:
package com.jb51.cc; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClasspathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClasspathXmlApplicationContext("Beans.xml"); TextEditor te = (TextEditor) context.getBean("textEditor"); te.spellCheck(); } }
以下是配置文件beans.xml文件里面有配置为基于setter 注入,但使用内部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-3.0.xsd"> <!-- DeFinition for textEditor bean using inner bean --> <bean id="textEditor"> <property name="spellChecker"> <bean id="spellChecker"/> </property> </bean> </beans>
创建源代码和bean配置文件来完成,让我们运行应用程序。如果一切顺利,这将打印以下信息:
Inside SpellChecker constructor. Inside setSpellChecker. Inside checkSpelling.
关于详解Java的Spring框架中bean的注入集合和spring框架注入bean工作原理的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于Java Spring框架创建项目与Bean的存储与读取详解、JavaWeb_(Spring框架)在Struts+Hibernate框架中引入Spring框架、Java的Spring框架中AOP项目的一般配置和部署教程、Java的Spring框架中bean的继承与内部bean的注入的相关知识,请在本站寻找。
本文标签: